Initial sshsm project structure 97/30897/3
authorNingSun <ning.sun@intel.com>
Thu, 8 Feb 2018 16:34:03 +0000 (08:34 -0800)
committerNingSun <ning.sun@intel.com>
Thu, 8 Feb 2018 17:14:52 +0000 (09:14 -0800)
Issue-ID: AAF-94
Change-Id: I5e82fff418e7567b161acf9b98013a9b85ffc5b4
Signed-off-by: NingSun <ning.sun@intel.com>
559 files changed:
.gitreview [new file with mode: 0644]
Adapter/README [new file with mode: 0644]
README.md [new file with mode: 0644]
SoftHSMv2/.appveyor.yml [new file with mode: 0644]
SoftHSMv2/.gitignore [new file with mode: 0644]
SoftHSMv2/.travis.yml [new file with mode: 0644]
SoftHSMv2/FIPS-NOTES.md [new file with mode: 0644]
SoftHSMv2/LICENSE [new file with mode: 0644]
SoftHSMv2/Makefile.am [new file with mode: 0644]
SoftHSMv2/NEWS [new file with mode: 0644]
SoftHSMv2/OSX-NOTES.md [new file with mode: 0644]
SoftHSMv2/README.md [new file with mode: 0644]
SoftHSMv2/WIN32-NOTES.md [new file with mode: 0644]
SoftHSMv2/aes_wrap_key_with_pad/README [new file with mode: 0644]
SoftHSMv2/aes_wrap_key_with_pad/botan-diff [new file with mode: 0644]
SoftHSMv2/autogen.sh [new file with mode: 0644]
SoftHSMv2/configure.ac [new file with mode: 0644]
SoftHSMv2/m4/acx_64bit.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_aes_gcm.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_ecc.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_gnump.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_gost.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_rawpss.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_botan_rfc5649.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_cppunit.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_crypto_backend.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_dlopen.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_non_paged_memory.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_openssl.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_openssl_ecc.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_openssl_fips.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_openssl_gost.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_openssl_rfc5649.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_p11kit.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_pedantic.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_prefixhack.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_sqlite3.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_strict.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_visibility.m4 [new file with mode: 0644]
SoftHSMv2/m4/acx_yield.m4 [new file with mode: 0644]
SoftHSMv2/m4/ax_cxx_compile_stdcxx_11.m4 [new file with mode: 0644]
SoftHSMv2/prepdist.sh [new file with mode: 0644]
SoftHSMv2/softhsm2.module.in [new file with mode: 0644]
SoftHSMv2/src/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/common/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/common/findslot.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/common/findslot.h [new file with mode: 0644]
SoftHSMv2/src/bin/common/getpw.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/common/getpw.h [new file with mode: 0644]
SoftHSMv2/src/bin/common/library.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/common/library.h [new file with mode: 0644]
SoftHSMv2/src/bin/dump/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/dump/common.h [new file with mode: 0644]
SoftHSMv2/src/bin/dump/softhsm2-dump-db.1 [new file with mode: 0644]
SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/dump/softhsm2-dump-file.1 [new file with mode: 0644]
SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/dump/tables.h [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/base64.c [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1 [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h [new file with mode: 0644]
SoftHSMv2/src/bin/migrate/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/migrate/softhsm2-migrate.1 [new file with mode: 0644]
SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/migrate/softhsm2-migrate.h [new file with mode: 0644]
SoftHSMv2/src/bin/util/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util-botan.h [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util-ossl.h [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util.1 [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/util/softhsm2-util.h [new file with mode: 0644]
SoftHSMv2/src/bin/win32/getopt.cpp [new file with mode: 0644]
SoftHSMv2/src/bin/win32/getopt.h [new file with mode: 0644]
SoftHSMv2/src/bin/win32/getpassphase.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/P11Attributes.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/P11Attributes.h [new file with mode: 0644]
SoftHSMv2/src/lib/P11Objects.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/P11Objects.h [new file with mode: 0644]
SoftHSMv2/src/lib/SoftHSM.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/SoftHSM.h [new file with mode: 0644]
SoftHSMv2/src/lib/access.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/access.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/Configuration.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/Configuration.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/HandleFactory.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/common/MutexFactory.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/MutexFactory.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/Serialisable.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/SimpleConfigLoader.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/fatal.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/fatal.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/log.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/log.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/osmutex.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/common/osmutex.h [new file with mode: 0644]
SoftHSMv2/src/lib/common/softhsm2.conf.5.in [new file with mode: 0644]
SoftHSMv2/src/lib/common/softhsm2.conf.in [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AESKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AESKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/AsymmetricParameters.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanAES.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanAES.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDES.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDES.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDH.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDH.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDH.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDH.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOST.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOST.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMAC.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMAC.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMD5.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMD5.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRNG.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRNG.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA1.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA1.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA224.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA224.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA256.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA256.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA384.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA384.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA512.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSHA512.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanUtil.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/BotanUtil.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/Botan_ecb.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/Botan_ecb.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/Botan_rounding.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/CryptoFactory.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/CryptoFactory.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DESKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DESKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHParameters.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHParameters.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DHPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAParameters.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAParameters.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/DSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECParameters.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECParameters.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/ECPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/GOSTPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/HashAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/MacAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLAES.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLAES.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLCMAC.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLComp.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLComp.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDES.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDES.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDH.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDH.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECDH.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECDH.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECDSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOST.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOST.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLHMAC.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLMD5.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLMD5.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRNG.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRNG.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSA.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSA.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA1.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA224.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA256.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA384.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLSHA512.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLUtil.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/OSSLUtil.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/PrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/PublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RNG.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAParameters.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAParameters.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAPrivateKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/RSAPublicKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/SymmetricKey.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/SymmetricKey.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/odd.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/AESTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/AESTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DESTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DESTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DHTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DHTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DSATests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/DSATests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ECDHTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ECDSATests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/GOSTTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/HashTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/HashTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/MacTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/MacTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/RNGTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/RNGTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/RSATests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/RSATests.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/chisq.c [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/cryptotest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ent.c [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/ent.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/iso8859.c [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/iso8859.h [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/randtest.c [new file with mode: 0644]
SoftHSMv2/src/lib/crypto/test/randtest.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/ByteString.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/ByteString.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/RFC4880.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/RFC4880.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/SecureAllocator.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/SecureDataManager.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/salloc.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/salloc.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/Handle.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/Handle.h [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/HandleManager.h [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/handle_mgr/test/handlemgrtest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/main.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DB.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DB.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DBObject.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DBObject.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DBToken.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/DBToken.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/Directory.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/Directory.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/File.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/File.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/FindOperation.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/FindOperation.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/Generation.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/Generation.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSAttribute.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSAttribute.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSAttributes.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSObject.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSPathSep.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSToken.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/OSToken.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectFile.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectFile.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectStore.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectStore.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectStoreToken.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/ObjectStoreToken.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/SessionObject.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/SessionObject.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/SessionObjectStore.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/SessionObjectStore.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/UUID.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/UUID.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBObjectTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DBTokenTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/DirectoryTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/FileTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/FileTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/OSTokenTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/UUIDTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/object_store/test/objstoretest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/pkcs11/cryptoki.h [new file with mode: 0644]
SoftHSMv2/src/lib/pkcs11/pkcs11.h [new file with mode: 0644]
SoftHSMv2/src/lib/pkcs11/pkcs11f.h [new file with mode: 0644]
SoftHSMv2/src/lib/pkcs11/pkcs11t.h [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/Session.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/Session.h [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/SessionManager.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/SessionManager.h [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/session_mgr/test/sessionmgrtest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/Slot.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/Slot.h [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/SlotManager.h [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/Token.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/Token.h [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/DeriveTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/DeriveTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/DigestTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/DigestTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/InfoTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/InfoTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/InitTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/InitTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/Makefile.am [new file with mode: 0644]
SoftHSMv2/src/lib/test/ObjectTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/ObjectTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/README [new file with mode: 0644]
SoftHSMv2/src/lib/test/RandomTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/RandomTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/SessionTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/SessionTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/SignVerifyTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/SignVerifyTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/TestsBase.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/TestsBase.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/TestsNoPINInitBase.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/TokenTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/TokenTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/UserTests.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/UserTests.h [new file with mode: 0644]
SoftHSMv2/src/lib/test/p11test.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/test/softhsm2-alt.conf.in [new file with mode: 0644]
SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32 [new file with mode: 0644]
SoftHSMv2/src/lib/test/softhsm2.conf.in [new file with mode: 0644]
SoftHSMv2/src/lib/test/softhsm2.conf.win32 [new file with mode: 0644]
SoftHSMv2/src/lib/test/tokens/dummy.in [new file with mode: 0644]
SoftHSMv2/src/lib/win32/dllmain.cc [new file with mode: 0644]
SoftHSMv2/src/lib/win32/setenv.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/win32/setenv.h [new file with mode: 0644]
SoftHSMv2/src/lib/win32/syslog.cpp [new file with mode: 0644]
SoftHSMv2/src/lib/win32/syslog.h [new file with mode: 0644]
SoftHSMv2/testing/appveyor/APPVEYOR-NOTES.MD [new file with mode: 0644]
SoftHSMv2/testing/appveyor/appveyor_build.bat [new file with mode: 0644]
SoftHSMv2/testing/appveyor/appveyor_download_requirements.ps1 [new file with mode: 0644]
SoftHSMv2/testing/build-botan.sh [new file with mode: 0644]
SoftHSMv2/testing/build-softhsm2.sh [new file with mode: 0644]
SoftHSMv2/testing/lib.sh [new file with mode: 0644]
SoftHSMv2/testing/travis/travis.sh [new file with mode: 0644]
SoftHSMv2/win32/.gitignore [new file with mode: 0644]
SoftHSMv2/win32/Configure.py [new file with mode: 0644]
SoftHSMv2/win32/config.h.in [new file with mode: 0644]
SoftHSMv2/win32/convarch/convarch.vcxproj.filters.in [new file with mode: 0644]
SoftHSMv2/win32/convarch/convarch.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/convarch/convarch.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/dump/dump.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/dump/dump.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/dump/dump.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/keyconv/keyconv.vcxproj.filters.in [new file with mode: 0644]
SoftHSMv2/win32/keyconv/keyconv.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/keyconv/keyconv.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/p11test/p11test.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/p11test/p11test.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/p11test/p11test.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/softhsm2.sln.in [new file with mode: 0644]
SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.filters [new file with mode: 0644]
SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.user [new file with mode: 0644]
SoftHSMv2/win32/util/util.vcxproj.filters.in [new file with mode: 0644]
SoftHSMv2/win32/util/util.vcxproj.in [new file with mode: 0644]
SoftHSMv2/win32/util/util.vcxproj.user [new file with mode: 0644]
TPM2-Plugin/README [new file with mode: 0644]

diff --git a/.gitreview b/.gitreview
new file mode 100644 (file)
index 0000000..5b40e19
--- /dev/null
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.onap.org
+port=29418
+project=aaf/sshsm.git
+
diff --git a/Adapter/README b/Adapter/README
new file mode 100644 (file)
index 0000000..0851e1e
--- /dev/null
@@ -0,0 +1,3 @@
+## Introduction
+
+This is an adapatation layer between SoftHSM and TPM2-Plugin.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..4f2c0d7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# SoftHSMv2 + TPM-Plugin
+## Introduction
+
+## Installation
+
+### Configure
+
+### Compile
+
+### Install
+
+
+
+
+## Note
+SoftHSMv2 is cloned from https://github.com/opendnssec/SoftHSMv2.git 
+with commit 6eb01f906ea112572b7bd80ca7b43982f1a160d6  
diff --git a/SoftHSMv2/.appveyor.yml b/SoftHSMv2/.appveyor.yml
new file mode 100644 (file)
index 0000000..121d805
--- /dev/null
@@ -0,0 +1,63 @@
+version: 2.2.{build}
+configuration: Release
+platform:
+- x86
+- x64
+init:
+- ps: >-
+    If ($env:Platform -Match "x86") {
+            $env:VCVARS_PLATFORM="x86"
+            $env:MSBUILD_PLATFORM="Win32"
+            $env:ENV_PLATFORM="x86"
+            $env:CONFIGURE_OPTIONS="disable-debug $env:ADDITIONAL_CONFIGURE_OPTIONS"
+    } Else {
+            $env:VCVARS_PLATFORM="amd64"
+            $env:MSBUILD_PLATFORM="x64"
+            $env:ENV_PLATFORM="x64"
+            $env:CONFIGURE_OPTIONS="enable-64bit disable-debug $env:ADDITIONAL_CONFIGURE_OPTIONS"
+    }
+
+
+    $CURRENT_DIR_PATH = (Get-Item -Path ".\" -Verbose).FullName
+
+    $env:BUILD_DIR = Join-Path $CURRENT_DIR_PATH build
+
+    $env:CRYPTO_PACKAGE= "$env:CRYPTO_PACKAGE_NAME-$env:ENV_PLATFORM.zip"
+
+    $env:CRYPTO_PACKAGE_PATH = Join-Path $env:BUILD_DIR "$env:CRYPTO_PACKAGE_NAME-$env:ENV_PLATFORM"
+
+    $env:CPPUNIT_VERSION_NAME = "CppUnit-1.13.2"
+
+    $env:CPPUNIT_PACKAGE_NAME = "cppunit-1.13.2"
+
+    $env:CPPUNIT_PACKAGE = "$env:CPPUNIT_PACKAGE_NAME-$env:ENV_PLATFORM.zip"
+
+    $env:PYTHON_PATH = Join-Path $env:BUILD_DIR python
+
+    $env:CPPUNIT_PATH = Join-Path $env:BUILD_DIR "$env:CPPUNIT_PACKAGE_NAME-$env:ENV_PLATFORM"
+
+    $env:PYTHON_EXE = Join-Path $env:PYTHON_PATH python.exe
+
+    $env:RELEASE_DIR=Join-Path $env:BUILD_DIR "SoftHSMv2-$env:ENV_PLATFORM"
+
+    $env:CONFIGURE_OPTIONS = "$env:CONFIGURE_OPTIONS with-crypto-backend=$env:CRYPTO_BACKEND with-$env:CRYPTO_BACKEND=$env:CRYPTO_PACKAGE_PATH\ with-cppunit=$env:CPPUNIT_PATH\"
+environment:
+  matrix:
+  - CRYPTO_BACKEND: openssl
+    PACKAGE_VERSION_NAME: OpenSSL-1.0.2j
+    CRYPTO_PACKAGE_NAME: openssl-1.0.2j
+  - CRYPTO_BACKEND: botan
+    PACKAGE_VERSION_NAME: Botan-1.10.13
+    CRYPTO_PACKAGE_NAME: botan-1.10.13
+  - CRYPTO_BACKEND: openssl
+    PACKAGE_VERSION_NAME: OpenSSL-1.1.0b
+    CRYPTO_PACKAGE_NAME: openssl-1.1.0b
+    ADDITIONAL_CONFIGURE_OPTIONS: disable-gost
+install:
+- cmd: powershell -File testing/appveyor/appveyor_download_requirements.ps1
+build_script:
+- cmd: testing/appveyor/appveyor_build.bat
+test: off
+artifacts:
+- path: build/SoftHSMv2-$(Platform)
+  name: SoftHSMv2-$(PACKAGE_VERSION_NAME)-$(Platform)
diff --git a/SoftHSMv2/.gitignore b/SoftHSMv2/.gitignore
new file mode 100644 (file)
index 0000000..88488d9
--- /dev/null
@@ -0,0 +1,80 @@
+# Automake, autoconf, libtool
+Makefile
+Makefile.in
+core
+acinclude.m4
+aclocal.m4
+autom4te.cache
+compile
+py-compile
+confdefs.h
+config.*
+!win32+botan/config.h
+!win32+openssl/config.h
+configure
+conftest
+conftest.c
+depcomp
+install-sh
+libtool
+libtool.m4
+lt*.m4
+ltmain.sh
+missing
+mkinstalldirs
+stamp-h*
+obj
+test-driver
+.deps
+.libs
+
+# Object files
+*.lo
+*.o
+
+# Libraries
+*.lib
+*.la
+*.a
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Test outputs
+*.log
+*.trs
+test-results.xml
+
+# Temporary files
+*~
+
+# Building directories
+build
+Botan-*
+ROOT
+
+# Specifics
+softhsm2.module
+src/bin/common/.dirstamp
+src/bin/dump/softhsm2-dump-db
+src/bin/dump/softhsm2-dump-file
+src/bin/keyconv/softhsm2-keyconv
+src/bin/util/softhsm2-util
+src/lib/common/.dirstamp
+src/lib/common/softhsm2.conf
+src/lib/common/softhsm2.conf.5
+src/lib/crypto/.dirstamp
+src/lib/crypto/test/cryptotest
+src/lib/data_mgr/test/datamgrtest
+src/lib/handle_mgr/test/handlemgrtest
+src/lib/object_store/test/objstoretest
+src/lib/session_mgr/test/sessionmgrtest
+src/lib/slot_mgr/test/slotmgrtest
+src/lib/test/p11test
+src/lib/test/softhsm2-alt.conf
+src/lib/test/softhsm2.conf
+src/lib/test/tokens/64d6c3fe-1575-1736-1d26-5ccb28440ea7/
+src/lib/test/tokens/dummy
diff --git a/SoftHSMv2/.travis.yml b/SoftHSMv2/.travis.yml
new file mode 100644 (file)
index 0000000..13f50a5
--- /dev/null
@@ -0,0 +1,13 @@
+language: cpp
+compiler:
+  - gcc
+  - clang
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install build-essential autoconf automake libtool libcppunit-dev libsqlite3-dev sqlite3 libbotan1.10-dev libssl-dev p11-kit
+script: sh testing/travis/travis.sh
+env:
+  - CRYPTO=openssl OBJSTORE=file
+  - CRYPTO=openssl OBJSTORE=sqlite
+  - CRYPTO=botan   OBJSTORE=file
+  - CRYPTO=botan   OBJSTORE=sqlite
diff --git a/SoftHSMv2/FIPS-NOTES.md b/SoftHSMv2/FIPS-NOTES.md
new file mode 100644 (file)
index 0000000..1827a3b
--- /dev/null
@@ -0,0 +1,56 @@
+# FIPS 140-2
+
+The OpenSSL crypto backend can be a FIPS 140-2 capable library,
+cf. the OpenSSL FIPS 140 documents SecurityPolicy and UserGuide.
+
+## Introduction
+
+Please read the OpenSSL FIPS 140 documents about to get
+a FIPS Capable OpenSSL library.
+
+## Hard points
+
+Reread the OpenSSL FIPS 140 documents as they are hard to apply.
+
+Note the following is for Unix/Linux.
+
+Now I suppose you have a >= 1.0.1e capable static library (a
+dynamic library is far easier but always possible and often
+dubious from a security point of view... BTW if you have built
+a FIPS Capable OpenSSL library you should not be afraid of
+extra complexity :-).
+
+Do not forget to compile OpenSSL with position indepent code
+(aka PIC) as the libsofthsm.so requires it. The FIPS module
+canister is already compiled this way.
+
+A usual issue is the C++ compiler not compiling .c files as C code.
+A simple test can show this, put in foo.c file this code:
+
+foo() { char *x = "ab"; }
+
+and compile with the C and C++ compilers with all warnings:
+the C++ compiler should raise an extra warning or error about
+the no type for foo() and/or for the char* string constant.
+
+When this raises some errors in the fispld script, you have to
+insert '-x c' and '-x none' before and after each .c file
+in the C++ commands, for instance using this wrapper:
+
+-------------------------------- cut here --------------------------------
+#!/bin/sh
+
+commands="g++"
+
+for elem in $@
+do
+ case $elem in
+   *.c) commands+=" -x c $elem -x none";;
+   *) commands+=" $elem";;
+ esac
+done
+
+exec $commands
+-------------------------------- end --------------------------------
+
+In any cases you have to set CC and CXX to fipsld.
diff --git a/SoftHSMv2/LICENSE b/SoftHSMv2/LICENSE
new file mode 100644 (file)
index 0000000..be4c168
--- /dev/null
@@ -0,0 +1,28 @@
+Copyright (c) 2010 .SE, The Internet Infrastructure Foundation
+                   http://www.iis.se
+
+Copyright (c) 2010 SURFnet bv
+                   http://www.surfnet.nl/en
+
+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.
diff --git a/SoftHSMv2/Makefile.am b/SoftHSMv2/Makefile.am
new file mode 100644 (file)
index 0000000..a6573a3
--- /dev/null
@@ -0,0 +1,65 @@
+ACLOCAL_AMFLAGS = -I m4
+
+MAINTAINERCLEANFILES = \
+        config.log config.status softhsm2.module \
+        $(srcdir)/Makefile.in \
+        $(srcdir)/config.h.in $(srcdir)/config.h.in~ \
+        $(srcdir)/configure \
+        $(srcdir)/install-sh $(srcdir)/ltmain.sh $(srcdir)/missing \
+        $(srcdir)/depcomp $(srcdir)/aclocal.m4 $(srcdir)/compile \
+        $(srcdir)/config.guess $(srcdir)/config.sub
+
+SUBDIRS = src
+
+if WITH_P11KIT
+p11moddir = @P11KIT_PATH@
+p11mod_DATA = softhsm2.module
+endif
+
+EXTRA_DIST =   $(srcdir)/aes_wrap_key_with_pad/botan-diff \
+               $(srcdir)/aes_wrap_key_with_pad/README \
+               $(srcdir)/FIPS-NOTES.md \
+               $(srcdir)/LICENSE \
+               $(srcdir)/m4/*.m4 \
+               $(srcdir)/OSX-NOTES.md \
+               $(srcdir)/README.md \
+               $(srcdir)/win32/config.h.in \
+               $(srcdir)/win32/Configure.py \
+               $(srcdir)/win32/convarch/convarch.vcxproj.in \
+               $(srcdir)/win32/convarch/convarch.vcxproj.filters.in \
+               $(srcdir)/win32/convarch/convarch.vcxproj.user \
+               $(srcdir)/win32/cryptotest/cryptotest.vcxproj.in \
+               $(srcdir)/win32/cryptotest/cryptotest.vcxproj.filters \
+               $(srcdir)/win32/cryptotest/cryptotest.vcxproj.user \
+               $(srcdir)/win32/datamgrtest/datamgrtest.vcxproj.in \
+               $(srcdir)/win32/datamgrtest/datamgrtest.vcxproj.filters \
+               $(srcdir)/win32/datamgrtest/datamgrtest.vcxproj.user \
+               $(srcdir)/win32/dump/dump.vcxproj.in \
+               $(srcdir)/win32/dump/dump.vcxproj.filters \
+               $(srcdir)/win32/dump/dump.vcxproj.user \
+               $(srcdir)/win32/handlemgrtest/handlemgrtest.vcxproj.in \
+               $(srcdir)/win32/handlemgrtest/handlemgrtest.vcxproj.filters \
+               $(srcdir)/win32/handlemgrtest/handlemgrtest.vcxproj.user \
+               $(srcdir)/win32/keyconv/keyconv.vcxproj.in \
+               $(srcdir)/win32/keyconv/keyconv.vcxproj.filters.in \
+               $(srcdir)/win32/keyconv/keyconv.vcxproj.user \
+               $(srcdir)/win32/objstoretest/objstoretest.vcxproj.in \
+               $(srcdir)/win32/objstoretest/objstoretest.vcxproj.filters \
+               $(srcdir)/win32/objstoretest/objstoretest.vcxproj.user \
+               $(srcdir)/win32/p11test/p11test.vcxproj.in \
+               $(srcdir)/win32/p11test/p11test.vcxproj.filters \
+               $(srcdir)/win32/p11test/p11test.vcxproj.user \
+               $(srcdir)/win32/sessionmgrtest/sessionmgrtest.vcxproj.in \
+               $(srcdir)/win32/sessionmgrtest/sessionmgrtest.vcxproj.filters \
+               $(srcdir)/win32/sessionmgrtest/sessionmgrtest.vcxproj.user \
+               $(srcdir)/win32/slotmgrtest/slotmgrtest.vcxproj.in \
+               $(srcdir)/win32/slotmgrtest/slotmgrtest.vcxproj.filters \
+               $(srcdir)/win32/slotmgrtest/slotmgrtest.vcxproj.user \
+               $(srcdir)/win32/softhsm2/softhsm2.vcxproj.in \
+               $(srcdir)/win32/softhsm2/softhsm2.vcxproj.filters \
+               $(srcdir)/win32/softhsm2/softhsm2.vcxproj.user \
+               $(srcdir)/win32/softhsm2.sln.in \
+               $(srcdir)/win32/util/util.vcxproj.in \
+               $(srcdir)/win32/util/util.vcxproj.filters.in \
+               $(srcdir)/win32/util/util.vcxproj.user \
+               $(srcdir)/WIN32-NOTES.md
diff --git a/SoftHSMv2/NEWS b/SoftHSMv2/NEWS
new file mode 100644 (file)
index 0000000..5d209ec
--- /dev/null
@@ -0,0 +1,292 @@
+NEWS for SoftHSM -- History of user visible changes
+
+SoftHSM develop
+
+* Issue #140: Support for CKA_ALLOWED_MECHANISMS.
+  (Patch from Brad Hess)
+* Issue #141: Support CKA_ALWAYS_AUTHENTICATE for private key objects.
+* Issue #220: Support for CKM_DES3_CMAC and CKM_AES_CMAC.
+* Issue #226: Configuration option for Windows build to enable build with
+  static CRT (/MT).
+* Issue #325: Support for CKM_AES_GCM.
+* Issue #334: Document that initialized tokens will be reassigned to another
+  slot (based on the token serial number).
+* Issue #335: Support for CKM_RSA_PKCS_PSS.
+  (Patch from Nikos Mavrogiannopoulos)
+* Issue #341: Import AES keys with softhsm2-util.
+  (Patch from Pavel Cherezov)
+* Issue #348: Document that OSX needs pkg-config to detect cppunit.
+* Issue #349: softhsm2-util will check the configuration and report any
+  issues before loading the PKCS#11 library.
+* Issue #351: Upgrade Botan in Jenkins build.
+
+Bugfixes:
+* Issue #345: Private objects are presented to security officer in search
+  results.
+* Issue #358: Race condition when multiple applications are creating and
+  reading object files.
+
+
+SoftHSM 2.3.0 - 2017-07-03
+
+* Issue #130: Upgraded to PKCS#11 v2.40.
+  * Minor changes to some return values.
+  * Added CKA_DESTROYABLE to all objects. Used by C_DestroyObject().
+  * Added CKA_PUBLIC_KEY_INFO to certificates, private, and public key
+    objects. Will be accepted from application, but SoftHSM will
+    currently not calculate it.
+* Issue #142: Support for CKM_AES_CTR.
+* Issue #155: Add unit tests for SessionManager.
+* Issue #189: C_DigestKey returns CKR_KEY_INDIGESTIBLE when key
+  attribute CKA_EXTRACTABLE = false. Whitelist SHA algorithms to allow
+  C_DigestKey in this case.
+* Issue #225: Show slot id after initialization.
+* Issue #247: Run AppVeyor (Windows CI) for each PR and merge.
+* Issue #257: Set CKA_DECRYPT/CKA_ENCRYPT flags on key import to true.
+  (Patch from Martin Domke)
+* Issue #261: Add support for libeaycompat lib for FIPS on Windows.
+  (Patch from Matt Hauck)
+* Issue #262: Support importing ECDSA P-521 in softhsm-util.
+* Issue #276: Support for Botan 2.0.
+* Issue #279: Editorial changes from Mountain Lion to Sierra.
+  (Patch from Mike Neumann)
+* Issue #283: More detailed error messages when initializing SoftHSM.
+* Issue #285: Support for LibreSSL.
+  (Patch from Alon Bar-Lev)
+* Issue #286: Update .gitignore.
+  (Patch from Alon Bar-Lev)
+* Issue #291: Change to enable builds and reports on new Jenkinks
+  environment.
+* Issue #293: Detect cppunit in autoconf.
+  (Patch from Alon Bar-Lev)
+* Issue #309: CKO_CERTIFICATE and CKO_PUBLIC_KEY now defaults to
+  CKA_PRIVATE=false.
+* Issue #314: Update README with information about logging.
+* Issue #330: Adjust log levels for failing to enumerate object store.
+  (Patch from Nikos Mavrogiannopoulos)
+
+Bugfixes:
+* Issue #216: Better handling of CRYPTO_set_locking_callback() for OpenSSL.
+* Issue #265: Fix deriving shared secret with ECC.
+* Issue #280: HMAC with sizes less than L bytes is strongly discouraged.
+  Set a lower bound equal to L bytes in ulMinKeySize and check it when
+  initializing the operation.
+* Issue #281: Fix test of p11 shared library.
+  (Patch from Lars Silvén)
+* Issue #289: Minor fix of 'EVP_CipherFinal_ex'.
+  (Patch from Viktor Tarasov)
+* Issue #297: Fix build with cppunit.
+  (Patch from Ludovic Rousseau)
+* Issue #302: Export PKCS#11 symbols from the library.
+  (Patch from Ludovic Rousseau)
+* Issue #305: Zero pad key to fit the block in CKM_AES_KEY_WRAP.
+* Issue #313: Detecting CppUnit when using Macports.
+  (Patch from mouse07410)
+
+
+SoftHSM 2.2.0 - 2016-12-05
+
+* Issue #143: Delete a token using softhsm2-util.
+* Issue #185: Change access mode bits for /var/lib/softhsm/tokens/
+  to 1777. All users can now create tokens, but only access their own.
+  (Patch from Rick van Rein)
+* Issue #186: Reinitializing a token will now keep the token, but all
+  token objects are deleted, the user PIN is removed and the token
+  label is updated.
+* Issue #190: Support for OpenSSL 1.1.0.
+* Issue #198: Calling C_GetSlotList with NULL_PTR will make sure that
+  there is always a slot with an uninitialized token available.
+* Issue #199: The token serial number will be used when setting the slot
+  number. The serial number is set after the token has been initialized.
+  (Patch from Lars Silvén)
+* Issue #203: Update the command utils to use the token label or serial
+  to find the token and its slot number.
+* Issue #209: Possibility to test other PKCS#11 implementations with the
+  CppUnit test.
+  (Patch from Lars Silvén)
+* Issue #223: Mark public key as non private by default.
+  (Patch from Nikos Mavrogiannopoulos)
+* Issue #230: Install p11-kit module, to disable use --disable-p11-kit.
+  (Patch from David Woodhouse)
+* Issue #237: Add windows continuous integration build.
+  (Patch from Peter Polačko)
+
+Bugfixes:
+* Issue #201: Missing new source file and test configuration in the
+  Windows build project.
+* Issue #205: ECDSA P-521 support for OpenSSL and better test coverage.
+* Issue #207: Fix segmentation faults in loadLibrary function.
+  (Patch from Jaroslav Imrich)
+* Issue #215: Update the Homebrew install notes for OSX.
+* Issue #218: Fix build warnings.
+* Issue #235: Add the libtool install command for OSX.
+  (Patch from Mark Wylde)
+* Issue #236: Use GetEnvironmentVariable instead of getenv on Windows.
+  (Patch from Jaroslav Imrich)
+* Issue #239: Crash on module unload with OpenSSL.
+  (Patch from David Woodhouse)
+* Issue #241: Added EXTRALIBS to Windows utils project.
+  (Patch from Peter Polačko)
+* Issue #250: C++11 not detected.
+* Issue #255: API changes in Botan 1.11.27.
+* Issue #260: Fix include guard to check WITH_FIPS.
+  (Patch from Matt Hauck)
+* Issue #268: p11test fails on 32-bit systems.
+* Issue #270: Build warning about "converting a string constant".
+* Issue #272: Fix C++11 check to look for unique_ptr.
+  (Patch from Matt Hauck)
+
+
+SoftHSM 2.1.0 - 2016-03-14
+
+* Issue #136: Improved guide and build scripts for Windows.
+  (Thanks to Jaroslav Imrich)
+* Issue #144: The password prompt in softhsm2-util can now be
+  interrupted (ctrl-c).
+* Issue #166: Add slots.removable config option.
+  (Patch from Sumit Bose)
+* Issue #180: Windows configure script improvements.
+  (Patch from Arnaud Grandville)
+
+Bugfixes:
+* Issue #128: Prioritize the return values in C_GetAttributeValue.
+  (Patch from Nicholas Wilson)
+* Issue #129: Fix errors reported by Visual Studio 2015.
+  (Patch from Jaroslav Imrich)
+* Issue #132: Handle the CKA_CHECK_VALUE correctly for certificates
+  and symmetric key objects.
+* Issue #154: Fix the Windows build and destruction order of objects.
+  (Patch from Arnaud Grandville)
+* Issue #162: Not possible to create certificate objects containing
+  CKA_CERTIFICATE_CATEGORY, CKA_NAME_HASH_ALGORITHM, or
+  CKA_JAVA_MIDP_SECURITY_DOMAIN.
+* Issue #163: Do not attempt decryption of empty byte strings.
+  (Patch from Michal Kepien)
+* Issue #165: Minor changes after a PVS-Studio code analysis, and
+  C_EncryptUpdate crash if no ciphered data is produced.
+  (Patch from Arnaud Grandville)
+* Issue #169: One-byte buffer overflow in call to EVP_DecryptUpdate.
+* Issue #171: Problem while closing library that is initialized but
+  improperly finalized.
+* Issue #173: Adjust return values for the template parsing.
+* Issue #174: C_DeriveKey() error with leading zero bytes.
+* Issue #177: CKA_NEVER_EXTRACTABLE set to CK_FALSE on objects
+  created with C_CreateObject.
+* Issue #182: Resolve compiler warning.
+  (Patch from Josh Datko)
+* Issue #184: Stop discarding the global OpenSSL libcrypto state.
+  (Patch from Michal Trojnara)
+* SOFTHSM-123: Fix library cleanup on BSD.
+
+
+SoftHSM 2.0.0 - 2015-07-17
+
+* SOFTHSM-121: Test cases for C_DecryptUpdate/C_DecryptFinal.
+* Support C_DecryptUpdate/C_DecryptFinal for symmetric algorithms.
+  (Patch from Thomas Calderon)
+
+Bugfixes:
+* SOFTHSM-120: Segfault after renaming variables.
+
+
+SoftHSM 2.0.0b3 - 2015-04-17
+
+* SOFTHSM-113: Support for Botan 1.11.15
+* SOFTHSM-119: softhsm2-util: Support ECDSA key import
+  (Patch from Magnus Ahltorp)
+* SUPPORT-139: Support deriving generic secrets, DES, DES2, DES3, and AES.
+  Using DH, ECDH or symmetric encryption.
+
+Bugfixes:
+* SOFTHSM-108: A marked as trusted certificate cannot be imported.
+* SOFTHSM-109: Unused parameter and variable warnings.
+* SOFTHSM-110: subdir-objects warnings from autoreconf.
+* SOFTHSM-111: Include FIPS-NOTES.md in dist.
+* SOFTHSM-112: CKM_AES_KEY_WRAP* conflict in pkcs11.h.
+* SOFTHSM-114: Fix memory leak in a test script.
+* SOFTHSM-115: Fix static analysis warnings.
+* SUPPORT-154: A marked as non-modifiable object cannot be generated.
+* SUPPORT-155: auto_ptr is deprecated in C++11, use unique_ptr.
+* SUPPORT-157: Derived secrets were truncated after encryption and
+  could thus not be decrypted.
+* Mutex should call MutexFactory wrapper functions.
+  (Patch from Jerry Lundström)
+* Return detailed error message to loadLibrary().
+  (Patch from Petr Spacek)
+
+
+SoftHSM 2.0.0b2 - 2014-12-28
+
+* SOFTHSM-50: OpenSSL FIPS support.
+* SOFTHSM-64: Updated build script for Windows.
+* SOFTHSM-100: Use --free with softhsm2-util to initialize the first
+  free token.
+* SOFTHSM-103: Allow runtime configuration of log level.
+* SOFTHSM-107: Support for CKM_<symcipher>_CBC_PAD.
+* Add support for CKM_RSA_PKCS_OAEP key un/wrapping.
+  (Patch from Petr Spacek)
+* Use OpenSSL EVP interface for AES key wrapping.
+  (Patch from Petr Spacek)
+* Allow reading configuration file from user's home directory.
+  (Patch from Nikos Mavrogiannopoulos)
+
+Bugfixes:
+* SOFTHSM-102: C_DeriveKey() uses OBJECT_OP_GENERATE.
+* Coverity found a number of issues.
+
+
+SoftHSM 2.0.0b1 - 2014-09-10
+
+* SOFTHSM-84: Check that all mandatory attributes are given during
+  the creation process.
+* SOFTHSM-92: Enable -fvisibility=hidden on per default
+* SUPPORT-137: Implement C_EncryptUpdate and C_EncryptFinal
+  (Patch from Martin Paljak)
+* Add support for CKM_RSA_PKCS key un/wrapping
+  (Patch from Petr Spacek)
+
+Bugfixes:
+* SOFTHSM-66: Attribute handling when using multiple threads
+* SOFTHSM-93: Invalid C++ object recycling.
+* SOFTHSM-95: umask affecting the calling application.
+* SOFTHSM-97: Check if Botan has already been initialized.
+* SOFTHSM-98: Handle mandatory attributes for DSA, DH, and ECDSA
+  correctly.
+* SOFTHSM-99: Binary encoding of GOST values.
+* SUPPORT-136: softhsm2-keyconv creates files with sensitive material
+  in insecure way.
+
+
+SoftHSM 2.0.0a2 - 2014-03-25
+
+* SOFTHSM-68: Display a better configure message when there is a 
+  version of Botan with a broken ECC/GOST/OID implementation.
+* SOFTHSM-70: Improved handling of the database backend.
+* SOFTHSM-71: Supporting Botan 1.11.
+* SOFTHSM-76: Do not generate RSA keys smaller than 1024 bit when 
+  using the Botan crypto backend.
+* SOFTHSM-83: Support CKA_VALUE_BITS for CKK_DH private key object.
+* SOFTHSM-85: Rename libsofthsm.so to libsofthsm2.so and prefix the
+  command line utilties with softhsm2-.
+* SOFTHSM-89: Use constants and not strings for signaling algorithms.
+* SUPPORT-129: Possible to use an empty template in C_GenerateKey.
+  The class and key type are inherited from the generation mechanism.
+  Some mechanisms do however require a length attribute. [SOFTHSM-88]
+* SUPPORT-131: Support RSA-PSS using SHA1, SHA224, SHA256, SHA384,
+  or SHA512. [SOFTHSM-87]
+
+Bugfixes:
+* SOFTHSM-39: Fix 64 bit build on sparc sun4v.
+* SOFTHSM-69: GOST did not work when you disabled ECC.
+* SOFTHSM-78: Correct the attribute checks for a number of objects.
+* SOFTHSM-80: Prevent segfault in OpenSSL GOST HMAC code.
+* SOFTHSM-91: Fix a warning from static code analysis.
+* Fixed a number of memory leaks.
+
+
+SoftHSM 2.0.0a1 - 2014-02-10
+
+This is the first alpha release of SoftHSMv2. It focuses on a higher 
+level of security by encrypting sensitive information and using 
+unswappable memory. There is also a more generalized crypto backend,
+where you can use Botan or OpenSSL.
diff --git a/SoftHSMv2/OSX-NOTES.md b/SoftHSMv2/OSX-NOTES.md
new file mode 100644 (file)
index 0000000..f1c7ee2
--- /dev/null
@@ -0,0 +1,182 @@
+# Building SoftHSMv2 on macOS 10.12.3 (Sierra)
+
+This document contains instructions for building SoftHSMv2 from the command
+line on macOS 10.12.3.
+
+This may work for other versions of OS X/macOS, but this has not been verified.
+
+## Command Line Tools
+
+We assume that XCode has been installed. To find out where Xcode keeps the C++
+compiler type the following at the command line:
+
+       $ xcode-select --print-path
+       /Applications/Xcode.app/Contents/Developer
+
+The gcc compiler in this case can be found at
+/Applications/Xcode.app/Contents/Developer/usr/bin/gcc
+
+Alternatively if you don't want to install XCode you could install command line
+tools for macOS that can be downloaded from Apple.
+
+e.g. currently the following package for the Sierra release of macOS is
+available for download.
+
+       Command_Line_Tools_macOS_10.12_for_Xcode_8.2.dmg
+
+This dmg file is ~150MB but it is at least orders of magnitude smaller than
+installing all of XCode.
+
+## Homebrew
+
+The libraries that come as part of macOS are rather old. We need to use more
+recent versions of these libraries to avoid unexpected failures during building
+and running.
+
+There is a community supported command line package manager for installing the
+dependencies we need. It's called homebrew. First we'll need to install it as
+follows:
+
+       $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+
+Now we need to install some dependencies
+
+       $ brew install automake
+       $ brew install pkg-config
+       $ brew install openssl
+       $ brew install sqlite
+       $ brew install cppunit
+       $ brew install libtool
+
+openssl, sqlite, and libtool are pre-installed on the system. The versions downloaded
+by brew are stored in an alternative location under /usr/local
+
+The only brew warning of note is for libtool:
+
+       ==> Caveats
+       In order to prevent conflicts with Apple's own libtool we have prepended a "g"
+       so, you have instead: glibtool and glibtoolize.
+
+Note: gblitoolize seems to be found in the configuration step below just fine. It's unclear
+if glibtool is used since autogen.sh generates its own libtool script that is used by make.
+
+During configure, the paths to the newly installed libraries need to be passed
+in so configure can actually find the libraries. We'll show how to do that
+later.
+
+## Cloning SoftHSMv2
+
+We now need to clone SoftHSMv2 from github.
+
+       $ git clone https://github.com/opendnssec/SoftHSMv2.git
+       $ cd SoftHSMv2
+
+## Configuring the build
+
+Start by installing autoconf in the source directory by executing the
+autogen.sh script.
+
+       $ sh ./autogen.sh
+
+If all went well a configure script should have been generated. To find out the
+options available for building issue the following command:
+
+       $ ./configure --help
+
+In the example below I will enable the optional token object store database
+backend.
+
+       $ ./configure --with-objectstore-backend-db \
+               --with-openssl=/usr/local/opt/openssl \
+               --with-sqlite3=/usr/local/opt/sqlite
+
+Now if for some reason the compilers are not found, do the following at the
+command line.
+
+       $ export CC="xcrun gcc"
+       $ export CPP="xcrun cpp"
+       $ export CXX="xcrun g++"
+       $ ./configure --with-objectstore-backend-db \
+               --with-openssl=/usr/local/opt/openssl \
+               --with-sqlite3=/usr/local/opt/sqlite
+
+By exporting these environment variables we are instructing configure to use
+the compilers stored inside the installed XCode.app.
+
+## Building and Testing SoftHSMv2
+
+Now we can build SoftHSMv2 by just executing make.
+
+       $ make
+
+And we can check that it works by running all tests.
+
+       $ make check
+
+To try a specific test, e.g. to check just the PKCS#11 test cases use the
+following make command:
+
+       $ make -C src/lib/test check
+
+Then change src/lib/test/softhsm2.conf so it contains the following lines.
+
+       # SoftHSM v2 configuration file
+       directories.tokendir = ./tokens
+       objectstore.backend = db
+       log.level = INFO
+       slots.removable = false
+
+Then change src/lib/test/softhsm2-alt.conf so it contains the following lines.
+
+       # SoftHSM v2 configuration file
+       directories.tokendir = ./tokens
+       objectstore.backend = db
+       log.level = INFO
+       slots.removable = true
+
+We are now ready to run the tests again.
+
+       $ make -C src/lib/test check
+
+Because the object store backend was changed from file to db we have used
+sqlite for storing the token objects. Verify this by looking in the sub-folders
+of src/lib/test/tokens There you should find a database file named sqlite3.db
+
+## Performance
+
+The file backend currently exhibits the best performance. It is normally at
+least twice as fast as the database backend.
+
+The idea behind storing token objects in a database is that it has advantages
+when a large number (> 100K) of keys are stored in a token. A database allows
+for selectively querying and loading in only a subset of the keys into memory.
+The file based storage backend reads in the complete contents of the token.
+Also because the database is only a single file, we should not hit any system
+limitations w.r.t. the number of files that can be stored in a file system.
+
+The database backend uses transactions to write changes to the token database.
+For modifiable attributes this will require a round trip to the database every
+time an attribute has been read as another process may have modified the given
+attribute.
+
+The database backend uses approximately 20% less memory because it will only
+load in object attributes on demand. For non-mutable attributes that is not a
+problem because once an object with its attributes is created those attributes
+won't change. On the other hand the mutable attributes of the object are always
+read when the object is accessed, making it slower because this will require a
+roundtrip to the database for every mutable attribute. Note that most
+attributes are non-mutable and especially the key material is non-mutable. So
+once this (encrypted !) material has been read into memory it will remain
+cached (encrypted !).
+
+Currently the query functionality for only retrieving a subset of the objects
+is not yet implemented. Therefore the database solution has no advantages
+w.r.t. the file based solution for large number of files other than the 20%
+less memory usage mentioned before.
+
+For applications that need the highest speed possible and only read/use the
+token, a solution would be to copy the whole of the token database to a
+ramdisk. This should only be used when the application doesn't modify the
+token, because a power-cycle of the host will wipe out the ramdisk.
+
+3-January-2017
diff --git a/SoftHSMv2/README.md b/SoftHSMv2/README.md
new file mode 100644 (file)
index 0000000..c8230e8
--- /dev/null
@@ -0,0 +1,149 @@
+# SoftHSM version 2
+
+SoftHSM is part of the OpenDNSSEC project. Read more at www.opendnssec.org.
+
+[![Travis Build Status](https://api.travis-ci.org/opendnssec/SoftHSMv2.png)](https://travis-ci.org/opendnssec/SoftHSMv2)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/opendnssec/SoftHSMv2?svg=true)](https://ci.appveyor.com/project/opendnssec/softhsmv2)
+
+## Introduction
+
+OpenDNSSEC handles and stores its cryptographic keys via the PKCS#11 interface.
+This interface specifies how to communicate with cryptographic devices such as
+HSM:s (Hardware Security Modules) and smart cards. The purpose of these devices
+is, among others, to generate cryptographic keys and sign information without
+revealing private-key material to the outside world. They are often designed to
+perform well on these specific tasks compared to ordinary processes in a normal
+computer.
+
+A potential problem with the use of the PKCS#11 interface is that it might
+limit the wide spread use of OpenDNSSEC, since a potential user might not be
+willing to invest in a new hardware device. To counter this effect, OpenDNSSEC
+is providing a software implementation of a generic cryptographic device with a
+PKCS#11 interface, the SoftHSM. SoftHSM is designed to meet the requirements of
+OpenDNSSEC, but can also work together with other cryptographic products
+because of the PKCS#11 interface.
+
+## Developers
+
+- Rickard Bellgrim (Knowit Secure AB, www.knowitgroup.com)
+- Francis Dupont (ISC, www.isc.org)
+- René Post (XPT Software and Consulting, www.xpt.nl)
+- Roland van Rijswijk (SURFnet bv, www.surfnet.nl)
+
+## Dependencies
+
+SoftHSM depends on a cryptographic library, Botan or OpenSSL.
+Minimum required versions:
+
+- Botan 1.10.0 
+- OpenSSL 1.0.0
+
+If you are using Botan, make sure that it has support for GNU MP (--with-gnump).
+This will improve the performance when doing public key operations.
+
+The GNU Autotools are also required for building the software.
+
+There is a migration tool for converting token databases from SoftHSMv1 into
+the new type of tokens. If this tool is built, then SQLite3 is required (>=
+3.4.2).
+
+## Installation
+
+### Configure
+
+Configure the installation/compilation scripts:
+
+       sh ./autogen.sh
+       ./configure
+
+Options:
+
+       --disable-non-paged-memory
+                               Disable non-paged memory for secure storage
+                               (default enabled)
+       --disable-ecc           Disable support for ECC (default enabled)
+       --disable-gost          Disable support for GOST (default enabled)
+       --disable-visibility    Disable hidden visibilty link mode [enabled]
+       --with-crypto-backend   Select crypto backend (openssl|botan)
+       --with-openssl=PATH     Specify prefix of path of OpenSSL
+       --with-botan=PATH       Specify prefix of path of Botan
+       --with-migrate          Build the migration tool. Used when migrating
+                               a SoftHSM v1 token database. Requires SQLite3
+       --with-objectstore-backend-db
+                               Build with database object store (SQLite3)
+       --with-sqlite3=PATH     Specify prefix of path of SQLite3
+       --disable-p11-kit       Disable p11-kit integration (default enabled)
+       --with-p11-kit=PATH     Specify install path of the p11-kit module, will
+                               override path given by pkg-config
+
+For more options:
+
+       ./configure --help
+
+
+### Compile
+
+Compile the source code using the following command:
+
+       make
+
+### Install Library
+
+Install the library using the follow command:
+
+       sudo make install
+
+### Configure
+
+The default location of the config file is /etc/softhsm2.conf. This location
+can be change by setting the environment variable.
+
+       export SOFTHSM2_CONF=/home/user/config.file
+
+Details on the configuration can be found in "man softhsm2.conf".
+
+Create the token directory you defined in your config file:
+
+      mkdir <token_dir>
+
+### Initialize Tokens
+
+Use either softhsm2-util or the PKCS#11 interface. The SO PIN can e.g. be used
+to re-initialize the token and the user PIN is handed out to the application so
+it can interact with the token.
+
+      softhsm2-util --init-token --slot 0 --label "My token 1"
+
+Type in SO PIN and user PIN. Once a token has been initialized, more slots will
+be added automatically with a new uninitialized token.
+
+Initialized tokens will be reassigned to another slot (based on the token
+serial number). It is recommended to find and interact with the token by
+searching for the token label or serial number in the slot list / token info.
+
+### Link
+
+Link to this library and use the PKCS#11 interface.
+
+
+## Backup
+
+All of the tokens and their objects are stored in the location given by
+softhsm2.conf. Backup can thus be done as a regular file copy.
+
+
+## Log information
+
+Log information is sent to syslog or the Windows event log and the log
+level is set in the configuration file. Each log event is prepended with
+the source file name and line number.
+
+
+## Building from the repository
+
+If the code is downloaded directly from the code repository, you have to
+prepare the configuration scripts before continuing with the real README.
+
+1. You need to install automake, autoconf, libtool, etc.
+2. Run the command 'sh autogen.sh'
+3. Continue reading this README.
diff --git a/SoftHSMv2/WIN32-NOTES.md b/SoftHSMv2/WIN32-NOTES.md
new file mode 100644 (file)
index 0000000..a3ce7ab
--- /dev/null
@@ -0,0 +1,311 @@
+# Building SoftHSM2 for Windows
+
+This document describes process of building both 32-bit and 64-bit versions of SoftHSM2 on 64-bit Windows 8.1 machine.
+Either OpenSSL or Botan can be used as the crypto backend.
+
+## Required software
+
+- [Visual Studio](https://www.visualstudio.com/products/visual-studio-community-vs) (2015 Community)
+- [GNU Privacy Guard for Windows](http://www.gpg4win.org/) (2.2.5)
+- [7-zip](http://www.7-zip.org/) (9.20)
+- [Strawberry Perl](http://strawberryperl.com/) (5.22.0.1)
+- [The Netwide Assembler](http://www.nasm.us/) (2.11.08)
+- [Python](https://www.python.org/downloads/windows/) (3.4.2)
+
+## Prepare working directories
+
+    mkdir C:\build\bin\
+    mkdir C:\build\src\
+
+## Build OpenSSL 1.0.2d static library
+
+Download [OpenSSL 1.0.2d](http://openssl.org/source/openssl-1.0.2d.tar.gz) with [its signature](http://openssl.org/source/openssl-1.0.2d.tar.gz.asc) into `C:\build\src\` directory and verify signature of the downloaded archive:
+
+    cd C:\build\src\
+    gpg --keyserver pgp.mit.edu --recv-keys 0E604491
+    gpg --verify openssl-1.0.2d.tar.gz.asc openssl-1.0.2d.tar.gz
+
+### 32-bit
+
+Extract archive `openssl-1.0.2d.tar.gz` into `C:\build\src\openssl-1.0.2d-x86` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x openssl-1.0.2d.tar.gz
+    "C:\Program Files\7-Zip\7z" x openssl-1.0.2d.tar
+    rename openssl-1.0.2d openssl-1.0.2d-x86
+    del openssl-1.0.2d.tar*
+
+In a **new command line window** build OpenSSL and install it into `C:\build\bin\openssl-1.0.2d-x86` directory:
+
+    cd C:\build\src\openssl-1.0.2d-x86
+    set PATH=%PATH%;C:\nasm
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+    perl Configure VC-WIN32 --prefix=C:\build\bin\openssl-1.0.2d-x86 enable-static-engine
+    ms\do_nasm
+    nmake /f ms\nt.mak
+    nmake /f ms\nt.mak test
+    nmake /f ms\nt.mak install
+
+## 64-bit
+
+Extract archive `openssl-1.0.2d.tar.gz` into `C:\build\src\openssl-1.0.2d-x64` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x openssl-1.0.2d.tar.gz
+    "C:\Program Files\7-Zip\7z" x openssl-1.0.2d.tar
+    rename openssl-1.0.2d openssl-1.0.2d-x64
+    del openssl-1.0.2d.tar*
+
+In a **new command line window** build OpenSSL and install it into `C:\build\bin\openssl-1.0.2d-x64` directory:
+
+    cd C:\build\src\openssl-1.0.2d-x64
+    set PATH=%PATH%;C:\nasm
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+    perl Configure VC-WIN64A --prefix=C:\build\bin\openssl-1.0.2d-x64 enable-static-engine
+    ms\do_win64a
+    nmake /f ms\nt.mak
+    nmake /f ms\nt.mak test
+    nmake /f ms\nt.mak install
+
+## Build OpenSSL 1.1.0a static library
+
+Download [OpenSSL 1.1.0a](https://www.openssl.org/source/openssl-1.1.0a.tar.gz) with [its signature](https://www.openssl.org/source/openssl-1.1.0a.tar.gz.asc) into `C:\build\src\` directory and verify signature of the downloaded archive:
+
+    cd C:\build\src\
+    gpg --keyserver pgp.mit.edu --recv-keys 0E604491
+    gpg --verify openssl-1.1.0a.tar.gz.asc openssl-1.1.0a.tar.gz
+
+### 32-bit
+
+Extract archive `openssl-1.1.0a.tar.gz` into `C:\build\src\openssl-1.1.0a-x86` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x openssl-1.1.0a.tar.gz
+    "C:\Program Files\7-Zip\7z" x openssl-1.1.0a.tar
+    rename openssl-1.1.0a openssl-1.1.0a-x86
+    del openssl-1.1.0a.tar*
+
+In a **new command line window** build OpenSSL and install it into `C:\build\bin\openssl-1.1.0a-x86` directory:
+
+    cd C:\build\src\openssl-1.1.0a-x86
+    set PATH=%PATH%;C:\nasm
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+    perl Configure VC-WIN32 --prefix=C:\build\bin\openssl-1.1.0a-x86 --openssldir=C:\build\bin\openssl-1.1.0a-x86\ssl no-shared
+    nmake
+    nmake test
+    nmake install
+
+## 64-bit
+
+Extract archive `openssl-1.1.0a.tar.gz` into `C:\build\src\openssl-1.1.0a-x64` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x openssl-1.1.0a.tar.gz
+    "C:\Program Files\7-Zip\7z" x openssl-1.1.0a.tar
+    rename openssl-1.1.0a openssl-1.1.0a-x64
+    del openssl-1.1.0a.tar*
+
+In a **new command line window** build OpenSSL and install it into `C:\build\bin\openssl-1.1.0a-x64` directory:
+
+    cd C:\build\src\openssl-1.1.0a-x64
+    set PATH=%PATH%;C:\nasm
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+    perl Configure VC-WIN64A --prefix=C:\build\bin\openssl-1.1.0a-x64 --openssldir=C:\build\bin\openssl-1.1.0a-x64\ssl no-shared
+    nmake
+    nmake test
+    nmake install
+       
+## Build Botan 1.10.10
+
+Download [Botan 1.10.10](http://botan.randombit.net/releases/Botan-1.10.10.tgz) with [its signature](http://botan.randombit.net/releases/Botan-1.10.10.tgz.asc) into `C:\build\src\` directory and verify signature of the downloaded archive:
+
+    cd C:\build\src\
+    gpg --keyserver pgp.mit.edu --recv-keys EFBADFBC
+    gpg --verify Botan-1.10.10.tgz.asc Botan-1.10.10.tgz
+
+### 32-bit
+
+Extract archive `Botan-1.10.10.tgz` into `C:\build\src\botan-1.10.10-x86` directory:
+
+    cd C:\build\src\
+    rename Botan-1.10.10.tgz Botan-1.10.10.tar.gz
+    "C:\Program Files\7-Zip\7z" x Botan-1.10.10.tar.gz
+    "C:\Program Files\7-Zip\7z" x Botan-1.10.10.tgz
+    rename Botan-1.10.10 botan-1.10.10-x86
+    del Botan-1.10.10.t*
+
+In a **new command line window as admin** build Botan and install it into `C:\build\bin\botan-1.10.10-x86` directory. Need to run the configure script as admin so it can link objects:
+
+    cd C:\build\src\botan-1.10.10-x86
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+    python configure.py --cc=msvc --cpu=x86 --prefix=C:\build\bin\botan-1.10.10-x86
+    nmake
+    nmake check
+    check.exe --validate
+    nmake install
+
+## 64-bit
+
+Extract archive `Botan-1.10.10.tgz` into `C:\build\src\botan-1.10.10-x64` directory:
+
+    cd C:\build\src\
+    rename Botan-1.10.10.tgz Botan-1.10.10.tar.gz
+    "C:\Program Files\7-Zip\7z" x Botan-1.10.10.tar.gz
+    "C:\Program Files\7-Zip\7z" x Botan-1.10.10.tgz
+    rename Botan-1.10.10 botan-1.10.10-x64
+    del Botan-1.10.10.t*
+
+In a **new command line window as admin** build Botan and install it into `C:\build\bin\botan-1.10.10-x64` directory. Need to run the configure script as admin so it can link objects:
+
+    cd C:\build\src\botan-1.10.10-x64
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+    python configure.py --cc=msvc --cpu=x64 --prefix=C:\build\bin\botan-1.10.10-x64
+    nmake
+    nmake check
+    check.exe --validate
+    nmake install
+
+## Build CppUnit 1.13.2 unicode library
+
+Download [CppUnit 1.13.2](http://dev-www.libreoffice.org/src/cppunit-1.13.2.tar.gz) into `C:\build\src\` directory.
+
+### 32-bit
+
+Extract archive `cppunit-1.13.2.tar.gz` into `C:\build\src\cppunit-1.13.2-x86` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x cppunit-1.13.2.tar.gz
+    "C:\Program Files\7-Zip\7z" x cppunit-1.13.2.tar
+    rename cppunit-1.13.2 cppunit-1.13.2-x86
+    del cppunit-1.13.2.tar*
+
+Open solution `C:\build\src\cppunit-1.13.2-x86\src\CppUnitLibraries2010.sln` in Visual Studio and rebuild the source with `Release Unicode\Win32` solution configuration.
+
+(If you want to compile SoftHSM with static CRT, then you must also compile CppUnit with static CRT. Change "Runtime Library" to "Multi-threaded (/MT)" in the project "cppunit". This will create some build errors for project "TestRunner", but that can be ignored since it is not used by SoftHSM.)
+
+Copy the results into `C:\build\bin\cppunit-1.13.2-x86` directory:
+
+    mkdir C:\build\bin\cppunit-1.13.2-x86\lib
+    xcopy C:\build\src\cppunit-1.13.2-x86\lib C:\build\bin\cppunit-1.13.2-x86\lib /E
+    mkdir C:\build\bin\cppunit-1.13.2-x86\include
+    xcopy C:\build\src\cppunit-1.13.2-x86\include C:\build\bin\cppunit-1.13.2-x86\include /E
+
+### 64-bit
+
+Extract archive `cppunit-1.13.2.tar.gz` into `C:\build\src\cppunit-1.13.2-x64` directory:
+
+    cd C:\build\src\
+    "C:\Program Files\7-Zip\7z" x cppunit-1.13.2.tar.gz
+    "C:\Program Files\7-Zip\7z" x cppunit-1.13.2.tar
+    rename cppunit-1.13.2 cppunit-1.13.2-x64
+    del cppunit-1.13.2.tar*
+
+Open solution `C:\build\src\cppunit-1.13.2-x64\src\CppUnitLibraries2010.sln` in Visual Studio and rebuild the source with `Release Unicode\x64` solution configuration.
+
+(If you want to compile SoftHSM with static CRT, then you must also compile CppUnit with static CRT. Change "Runtime Library" to "Multi-threaded (/MT)" in the project "cppunit". This will create some build errors for project "TestRunner", but that can be ignored since it is not used by SoftHSM.)
+
+Copy the results into `C:\build\bin\cppunit-1.13.2-x64` directory:
+
+    mkdir C:\build\bin\cppunit-1.13.2-x64\lib
+    xcopy C:\build\src\cppunit-1.13.2-x64\lib C:\build\bin\cppunit-1.13.2-x64\lib /E
+    mkdir C:\build\bin\cppunit-1.13.2-x64\include
+    xcopy C:\build\src\cppunit-1.13.2-x64\include C:\build\bin\cppunit-1.13.2-x64\include /E
+
+## Build SoftHSM
+
+Download the latest version of [SoftHSMv2](https://dist.opendnssec.org/source/) with its signature into `C:\build\src\` directory and verify signature of the downloaded archive:
+
+    cd C:\build\src\
+    gpg --keyserver pgp.mit.edu --recv-keys 4EE17CD2
+    gpg --verify softhsm-2.x.y.tar.gz.sig softhsm-2.x.y.tar.gz
+    "C:\Program Files\7-Zip\7z" x softhsm-2.x.y.tar.gz
+    "C:\Program Files\7-Zip\7z" x softhsm-2.x.y.tar
+    rename softhsm-2.x.y SoftHSMv2
+    del softhsm-2.x.y.tar*
+
+Or clone the source code from GitHub:
+
+    cd C:\build\src\
+    git clone https://github.com/opendnssec/SoftHSMv2.git
+       
+### 32-bit
+
+Configure build process in a **new command line window**:
+
+    cd C:\build\src\SoftHSMv2\win32\
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+
+OpenSSL (OpenSSL GOST engine does not support OpenSSL 1.1.0) or Botan crypto backend:
+
+    python Configure.py disable-debug disable-gost with-crypto-backend=openssl with-openssl=C:\build\bin\openssl-1.1.0a-x86\ with-cppunit=C:\build\bin\cppunit-1.13.2-x86\
+    python Configure.py disable-debug with-crypto-backend=botan with-botan=C:\build\bin\botan-1.10.10-x86\ with-cppunit=C:\build\bin\cppunit-1.13.2-x86\
+
+(Add option enable-static-runtime if you want to compile with static CRT (/MT))
+
+Open solution `C:\build\src\SoftHSMv2\win32\softhsm2.sln` in Visual Studio and rebuild the source with `Release\Win32` solution configuration.
+
+Verify the build by running the test programs:
+
+    C:\build\src\SoftHSMv2\win32\Release\cryptotest.exe
+    C:\build\src\SoftHSMv2\win32\Release\datamgrtest.exe
+    C:\build\src\SoftHSMv2\win32\Release\handlemgrtest.exe
+    C:\build\src\SoftHSMv2\win32\Release\objstoretest.exe
+    C:\build\src\SoftHSMv2\win32\Release\p11test.exe
+    C:\build\src\SoftHSMv2\win32\Release\sessionmgrtest.exe
+    C:\build\src\SoftHSMv2\win32\Release\slotmgrtest.exe
+
+Copy the results into `C:\build\bin\SoftHSMv2-x86` directory:
+
+    mkdir C:\build\bin\SoftHSMv2-x86
+    mkdir C:\build\bin\SoftHSMv2-x86\tokens
+    copy C:\build\src\SoftHSMv2\win32\Release\softhsm2.dll C:\build\bin\SoftHSMv2-x86\
+    copy C:\build\src\SoftHSMv2\win32\Release\softhsm2-dump-file.exe C:\build\bin\SoftHSMv2-x86\
+    copy C:\build\src\SoftHSMv2\win32\Release\softhsm2-keyconv.exe C:\build\bin\SoftHSMv2-x86\
+    copy C:\build\src\SoftHSMv2\win32\Release\softhsm2-util.exe C:\build\bin\SoftHSMv2-x86\
+    copy C:\build\src\SoftHSMv2\src\lib\common\softhsm2.conf.in C:\build\bin\SoftHSMv2-x86\softhsm2.conf
+
+Replace `@softhsmtokendir@` with `C:\build\bin\SoftHSMv2-x86\tokens` in the file `C:\build\bin\SoftHSMv2-x86\softhsm2.conf`
+
+Set the environment variable SOFTHSM2_CONF to `C:\build\bin\SoftHSMv2-x86\softhsm2.conf`
+
+### 64-bit
+
+Configure build process in a **new command line window**:
+
+    cd C:\build\src\SoftHSMv2\win32\
+    "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+
+OpenSSL (OpenSSL GOST engine does not support OpenSSL 1.1.0) or Botan crypto backend:
+
+    python Configure.py enable-64bit disable-debug disable-gost with-crypto-backend=openssl with-openssl=C:\build\bin\openssl-1.1.0a-x64\ with-cppunit=C:\build\bin\cppunit-1.13.2-x64\
+    python Configure.py enable-64bit disable-debug with-crypto-backend=botan with-botan=C:\build\bin\botan-1.10.10-x64\ with-cppunit=C:\build\bin\cppunit-1.13.2-x64\
+
+(Add option enable-static-runtime if you want to compile with static CRT (/MT))
+
+Open solution `C:\build\src\SoftHSMv2\win32\softhsm2.sln` in Visual Studio and rebuild the source with `Release\x64` solution configuration.
+
+Verify the build by running the test programs:
+
+    C:\build\src\SoftHSMv2\win32\x64\Release\cryptotest.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\datamgrtest.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\handlemgrtest.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\objstoretest.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\p11test.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\sessionmgrtest.exe
+    C:\build\src\SoftHSMv2\win32\x64\Release\slotmgrtest.exe
+
+Copy the results into `C:\build\bin\SoftHSMv2-x64` directory:
+
+    mkdir C:\build\bin\SoftHSMv2-x64
+    mkdir C:\build\bin\SoftHSMv2-x64\tokens
+    copy C:\build\src\SoftHSMv2\win32\x64\Release\softhsm2.dll C:\build\bin\SoftHSMv2-x64\
+    copy C:\build\src\SoftHSMv2\win32\x64\Release\softhsm2-dump-file.exe C:\build\bin\SoftHSMv2-x64\
+    copy C:\build\src\SoftHSMv2\win32\x64\Release\softhsm2-keyconv.exe C:\build\bin\SoftHSMv2-x64\
+    copy C:\build\src\SoftHSMv2\win32\x64\Release\softhsm2-util.exe C:\build\bin\SoftHSMv2-x64\
+    copy C:\build\src\SoftHSMv2\src\lib\common\softhsm2.conf.in C:\build\bin\SoftHSMv2-x64\softhsm2.conf
+
+Replace `@softhsmtokendir@` with `C:\build\bin\SoftHSMv2-x64\tokens` in the file `C:\build\bin\SoftHSMv2-x64\softhsm2.conf`
+
+Set the environment variable SOFTHSM2_CONF to `C:\build\bin\SoftHSMv2-x64\softhsm2.conf`
+
+## Continue reading in the README
diff --git a/SoftHSMv2/aes_wrap_key_with_pad/README b/SoftHSMv2/aes_wrap_key_with_pad/README
new file mode 100644 (file)
index 0000000..883cbf4
--- /dev/null
@@ -0,0 +1,7 @@
+Here are the patches to add advanced AES key wrap *with pad*, aka RFC 5649,
+to Botan (1.10, not 1.11 even it should be easy).
+PS: standardized (and approved) under the KWP name in NIST SP 800-38F.
+
+OpenSSL added support for RFC 5649 in commit
+d31fed73e25391cd71a0de488d88724db78f6f8a and it is waiting for nearest release.
+Some distributions backported the interface, e.g. Fedora and RHEL.
diff --git a/SoftHSMv2/aes_wrap_key_with_pad/botan-diff b/SoftHSMv2/aes_wrap_key_with_pad/botan-diff
new file mode 100644 (file)
index 0000000..bf03118
--- /dev/null
@@ -0,0 +1,340 @@
+--- src/constructs/rfc3394/rfc3394.h-dist      2013-11-10 17:06:11.000000000 +0100
++++ src/constructs/rfc3394/rfc3394.h   2013-12-22 02:14:50.000000000 +0100
+@@ -27,6 +27,13 @@
+                                              const SymmetricKey& kek,
+                                              Algorithm_Factory& af);
++/* overload with an extra initial value */
++
++SecureVector<byte> BOTAN_DLL rfc3394_keywrap(const MemoryRegion<byte>& key,
++                                           const byte iv[8],
++                                             const SymmetricKey& kek,
++                                             Algorithm_Factory& af);
++
+ /**
+ * Decrypt a key under a key encryption key using the algorithm
+ * described in RFC 3394
+@@ -40,6 +47,47 @@
+                                                const SymmetricKey& kek,
+                                                Algorithm_Factory& af);
++/* overload with an extra initial value */
++
++SecureVector<byte> BOTAN_DLL rfc3394_keyunwrap(const MemoryRegion<byte>& key,
++                                             const byte iv[8],
++                                               const SymmetricKey& kek,
++                                               Algorithm_Factory& af);
++
++/* overload with an extra initial value and integrity check value */
++
++SecureVector<byte> BOTAN_DLL rfc3394_keyunwrap(const MemoryRegion<byte>& key,
++                                             const byte iv[8],
++                                             byte icv[8],
++                                               const SymmetricKey& kek,
++                                               Algorithm_Factory& af);
++
++/**
++* Pad and encrypt a key under a key encryption key using the algorithm
++* described in RFC 5649
++*
++* @param key the plaintext key to encrypt
++* @param kek the key encryption key
++* @param af an algorithm factory
++* @return key encrypted under kek
++*/
++SecureVector<byte> BOTAN_DLL rfc5649_keywrap(const MemoryRegion<byte>& key,
++                                             const SymmetricKey& kek,
++                                             Algorithm_Factory& af);
++
++/**
++* Decrypt and unpad a key under a key encryption key using the algorithm
++* described in RFC 5649
++*
++* @param key the encrypted key to decrypt
++* @param kek the key encryption key
++* @param af an algorithm factory
++* @return key decrypted under kek
++*/
++SecureVector<byte> BOTAN_DLL rfc5649_keyunwrap(const MemoryRegion<byte>& key,
++                                               const SymmetricKey& kek,
++                                               Algorithm_Factory& af);
++
+ }
+ #endif
+--- src/constructs/rfc3394/rfc3394.cpp-dist    2013-11-10 17:06:11.000000000 +0100
++++ src/constructs/rfc3394/rfc3394.cpp 2013-12-22 03:46:13.000000000 +0100
+@@ -30,12 +30,35 @@
+       throw std::invalid_argument("Bad KEK length for NIST keywrap");
+    }
++BlockCipher* make_aesp(size_t keylength,
++                       Algorithm_Factory& af)
++   {
++   if(keylength == 16)
++      return af.make_block_cipher("AES-128");
++   else if(keylength == 24)
++      return af.make_block_cipher("AES-192");
++   else if(keylength == 32)
++      return af.make_block_cipher("AES-256");
++   else
++      throw std::invalid_argument("Bad KEK length for NIST keywrap with pad");
++   }
+ }
+ SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key,
+                                    const SymmetricKey& kek,
+                                    Algorithm_Factory& af)
+    {
++   byte iv[8];
++   for(size_t i = 0; i != 8; ++i)
++      iv[i] = 0xA6;
++   return rfc3394_keywrap(key, iv, kek, af);
++   }
++
++SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key,
++                                 const byte iv[8],
++                                   const SymmetricKey& kek,
++                                   Algorithm_Factory& af)
++   {
+    if(key.size() % 8 != 0)
+       throw std::invalid_argument("Bad input key size for NIST key wrap");
+@@ -48,7 +71,7 @@
+    SecureVector<byte> A(16);
+    for(size_t i = 0; i != 8; ++i)
+-      A[i] = 0xA6;
++      A[i] = iv[i];
+    copy_mem(&R[8], key.begin(), key.size());
+@@ -78,6 +101,29 @@
+                                      const SymmetricKey& kek,
+                                      Algorithm_Factory& af)
+    {
++   byte iv[8];
++   for(size_t i = 0; i != 8; ++i)
++      iv[i] = 0xA6;
++   return rfc3394_keyunwrap(key, iv, kek, af);
++   }
++
++SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key,
++                                   const byte iv[8],
++                                     const SymmetricKey& kek,
++                                     Algorithm_Factory& af)
++   {
++   byte icv[8];
++   for(size_t i = 0; i != 8; ++i)
++      icv[i] = iv[i];
++   return rfc3394_keyunwrap(key, iv, icv, kek, af);
++   }
++
++SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key,
++                                   const byte iv[8],
++                                   byte icv[8],
++                                     const SymmetricKey& kek,
++                                     Algorithm_Factory& af)
++   {
+    if(key.size() < 16 || key.size() % 8 != 0)
+       throw std::invalid_argument("Bad input key size for NIST key unwrap");
+@@ -113,10 +159,107 @@
+          }
+       }
+-   if(load_be<u64bit>(&A[0], 0) != 0xA6A6A6A6A6A6A6A6)
+-      throw Integrity_Failure("NIST key unwrap failed");
++   if(load_be<u64bit>(iv, 0) == load_be<u64bit>(icv, 0))
++      {
++      if(load_be<u64bit>(&A[0], 0) != load_be<u64bit>(iv, 0))
++          throw Integrity_Failure("NIST key unwrap failed");
++      }
++   else
++      store_be(load_be<u64bit>(&A[0], 0), icv);
+    return R;
+    }
++SecureVector<byte> rfc5649_keywrap(const MemoryRegion<byte>& key,
++                                   const SymmetricKey& kek,
++                                   Algorithm_Factory& af)
++   {
++   const size_t len = key.size() +
++      (key.size() % 8 == 0 ? 0 : (8 - key.size() % 8));
++
++   u32bit aivh = 0xA65959A6;
++   byte ivh[4] = { 0 };
++   store_be(aivh, ivh);
++   u32bit mli = key.size();
++   byte ivl[4] = { 0 };
++   store_be(mli, ivl);
++
++   if(len == 8)
++      {
++      std::auto_ptr<BlockCipher> aes(make_aesp(kek.length(), af));
++      aes->set_key(kek);
++
++      SecureVector<byte> buf(16);
++      copy_mem(&buf[0], ivh, 4);
++      copy_mem(&buf[4], ivl, 4);
++      copy_mem(&buf[8], key.begin(), key.size());
++
++      aes->encrypt(&buf[0]);
++
++      return buf;
++      }
++   else
++      {
++      MemoryVector<byte> buf(len);
++      copy_mem(&buf[0], key.begin(), key.size());
++      byte iv[8] = { 0 };
++      copy_mem(iv, ivh, 4);
++      copy_mem(&iv[4], ivl, 4);
++      return rfc3394_keywrap(buf, iv, kek, af);
++      }
++   }       
++
++SecureVector<byte> rfc5649_keyunwrap(const MemoryRegion<byte>& key,
++                                     const SymmetricKey& kek,
++                                     Algorithm_Factory& af)
++   {
++   if(key.size() < 16 || key.size() % 8 != 0)
++      throw std::invalid_argument("Bad input key size for NIST key unwrap with pad");
++
++   byte iv[8] = { 0 };
++   SecureVector<byte> out;
++
++   if(key.size() == 16)
++      {
++      std::auto_ptr<BlockCipher> aes(make_aesp(kek.length(), af));
++      aes->set_key(kek);
++
++      SecureVector<byte> buf(key);
++
++      aes->decrypt(&buf[0]);
++
++      copy_mem(iv, buf.begin(), 8);
++      out.resize(8);
++      copy_mem(&out[0], &buf[8], 8);
++      }
++   else
++      {
++      byte dummy[8] = { 1 };
++      try
++         {
++         out = rfc3394_keyunwrap(key, dummy, iv, kek, af);
++         }
++      catch(...)
++         {
++         throw Integrity_Failure("NIST key unwrap with pad failed");
++         } 
++      }
++
++   if(load_be<u32bit>(&iv[0], 0) != 0xA65959A6)
++      throw Integrity_Failure("NIST key unwrap with pad failed");
++
++   u32bit mli = load_be<u32bit>(iv, 1);
++   if(mli > out.size() || mli <= out.size() - 8)
++      throw Integrity_Failure("NIST key unwrap with pad failed");
++
++   size_t padlen = out.size() - mli;
++   byte zero[8] = { 0 };
++   clear_mem(zero, 8);
++   if(padlen && !same_mem(zero, &out[mli], padlen))
++      throw Integrity_Failure("NIST key unwrap with pad failed");
++
++   out.resize(mli);
++   return out;
++   }
++
+ }
+--- src/constructs/rfc3394/info.txt-dist       2013-11-10 17:06:11.000000000 +0100
++++ src/constructs/rfc3394/info.txt    2013-12-22 00:42:08.000000000 +0100
+@@ -1 +1,2 @@
+ define RFC3394_KEYWRAP
++define RFC5649_KEYWRAP
+--- checks/validate.cpp-dist   2013-11-10 17:06:11.000000000 +0100
++++ checks/validate.cpp        2013-12-22 02:15:12.000000000 +0100
+@@ -180,6 +180,68 @@
+    return ok;
+    }
++bool keywrap_withpad_test(const char* key_str,
++                          const char* expected_str,
++                          const char* kek_str)
++   {
++   std::cout << '.' << std::flush;
++
++   bool ok = true;
++
++#if defined(BOTAN_HAS_RFC5649_KEYWRAP)
++   try
++      {
++      SymmetricKey key(key_str);
++      SymmetricKey expected(expected_str);
++      SymmetricKey kek(kek_str);
++
++      Algorithm_Factory& af = global_state().algorithm_factory();
++
++      SecureVector<byte> enc = rfc5649_keywrap(key.bits_of(), kek, af);
++
++      if(enc != expected.bits_of())
++         {
++         std::cout << "NIST key wrap encryption failure: "
++                   << hex_encode(enc) << " != " << hex_encode(expected.bits_of()) << "\n";
++         ok = false;
++         }
++
++      SecureVector<byte> dec = rfc5649_keyunwrap(expected.bits_of(), kek, af);
++
++      if(dec != key.bits_of())
++         {
++         std::cout << "NIST key wrap decryption failure: "
++                   << hex_encode(dec) << " != " << hex_encode(key.bits_of()) << "\n";
++         ok = false;
++         }
++      }
++   catch(std::exception& e)
++      {
++      std::cout << e.what() << "\n";
++      }
++#endif
++
++   return ok;
++   }
++
++bool test_keywrap_withpad()
++   {
++   std::cout << "Testing NIST keywrap with pad: " << std::flush;
++
++   bool ok = true;
++
++   ok &= keywrap_withpad_test("C37B7E6492584340BED12207808941155068F738",
++                            "138BDEAA9B8FA7FC61F97742E72248EE5AE6AE5360D1AE6A5F54F373FA543B6A",
++                            "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8");
++
++   ok &= keywrap_withpad_test("466f7250617369",
++                            "AFBEB0F07DFBF5419200F2CCB50BB24F",
++                            "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8");
++
++   std::cout << "\n";
++   return ok;
++   }
++
+ bool test_bcrypt(RandomNumberGenerator& rng)
+    {
+ #if defined(BOTAN_HAS_BCRYPT)
+@@ -410,6 +472,12 @@
+       errors++;
+       }
++   if(should_pass && !test_keywrap_withpad())
++      {
++      std::cout << "NIST keywrap with pad tests failed" << std::endl;
++      errors++;
++      }
++
+    if(should_pass && !test_cryptobox(rng))
+       {
+       std::cout << "Cryptobox tests failed" << std::endl;
diff --git a/SoftHSMv2/autogen.sh b/SoftHSMv2/autogen.sh
new file mode 100644 (file)
index 0000000..01db361
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf --install --force
diff --git a/SoftHSMv2/configure.ac b/SoftHSMv2/configure.ac
new file mode 100644 (file)
index 0000000..7a9e665
--- /dev/null
@@ -0,0 +1,226 @@
+##################
+#                #
+#    Version     #
+#                #
+################
+
+# Program version
+
+define([SOFTHSM_VERSION_MAJOR], [2])
+define([SOFTHSM_VERSION_MINOR], [3])
+define([SOFTHSM_VERSION_FIX], [0])
+define([PACKAGE_SUFFIX], [])
+
+# Library version
+
+# Code changed:                      SOFTHSM_VERSION_REVISION++
+# Interface added/removed/changed:   SOFTHSM_VERSION_CURRENT++, SOFTHSM_VERSION_REVISION=0
+# Interface added:                   SOFTHSM_VERSION_AGE++
+# Interface removed:                 SOFTHSM_VERSION_AGE=0
+
+define([SOFTHSM_VERSION_CURRENT], [2])
+define([SOFTHSM_VERSION_AGE], [1])
+define([SOFTHSM_VERSION_REVISION], [3])
+
+##################
+#                #
+# Configure code #
+#                #
+##################
+
+# Init
+AC_PREREQ(2.61)
+AC_INIT([SoftHSM],[SOFTHSM_VERSION_MAJOR.SOFTHSM_VERSION_MINOR.SOFTHSM_VERSION_FIX[]PACKAGE_SUFFIX])
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_SRCDIR([src/Makefile.am])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+ACX_PREFIXHACK
+
+# Version info for the library
+VERSION_INFO="SOFTHSM_VERSION_CURRENT:SOFTHSM_VERSION_REVISION:SOFTHSM_VERSION_AGE"
+AC_SUBST(VERSION_INFO)
+
+# Checks for compilers
+AC_PROG_CC
+AC_PROG_CXX
+
+# Compiler flags
+ACX_PEDANTIC
+ACX_STRICT
+ACX_64BIT
+AX_CXX_COMPILE_STDCXX_11([noext],[optional])
+
+# Check for libraries (-ldl can be required by OpenSSL too)
+ACX_DLOPEN
+
+# Check for headers
+AC_CHECK_HEADERS([pthread.h])
+
+# What crypto backend to use and if we want to have support GOST
+ACX_CRYPTO_BACKEND
+
+# Non-paged memory for secure storage
+ACX_NON_PAGED_MEMORY
+
+# If the user want to have the migration tool
+# Requires SQLite3
+AC_ARG_WITH(migrate,
+       AC_HELP_STRING([--with-migrate],
+               [Build the migration tool. Requires SQLite3.]
+       ),
+       [build_migrate="${withval}"],
+       [build_migrate="no"]
+)
+AC_MSG_CHECKING(if building with softhsm2-migrate)
+if test "x${build_migrate}" = "xyes"; then
+       AC_MSG_RESULT(yes)
+       ACX_YIELD
+else
+       AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL([BUILD_MIGRATE], [test "x${build_migrate}" = "xyes"])
+
+# If the user wants to have the database storage backend
+AC_ARG_WITH([objectstore-backend-db],
+       AC_HELP_STRING([--with-objectstore-backend-db],
+               [Build with object store backend database (SQLite3).]
+       ),
+       [build_objectstore_backend_db="${withval}"],
+       [build_objectstore_backend_db="no"]
+)
+AC_MSG_CHECKING(if building database object store backend)
+if test "x${build_objectstore_backend_db}" = "xyes"; then
+       AC_MSG_RESULT(yes)
+       AC_DEFINE_UNQUOTED(
+               [HAVE_OBJECTSTORE_BACKEND_DB],
+               [1],
+               [Build with object store database backend.]
+       )
+else
+       AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL([BUILD_OBJECTSTORE_BACKEND_DB], [test "x${build_objectstore_backend_db}" = "xyes"])
+
+# Require SQLite3 if either building --with-migrate or --with-objectstore-backend-db
+AC_MSG_CHECKING(if SQLite3 required)
+if test "x${build_migrate}" = "xyes" -o "x${build_objectstore_backend_db}" = "xyes"; then
+       AC_MSG_RESULT(yes)
+       ACX_SQLITE3
+else
+       AC_MSG_RESULT(no)
+fi
+
+# Set visibility flags so only PKCS#11 entry points are exported
+ACX_VISIBILITY
+
+# If we should install the p11-kit module
+ACX_P11KIT
+
+# cppunit settings
+ACX_CPPUNIT
+
+# Set full directory paths
+full_sysconfdir=`eval eval eval eval eval echo "${sysconfdir}" | sed "s#NONE#${prefix}#" | sed "s#NONE#${ac_default_prefix}#"`
+full_localstatedir=`eval eval eval eval eval echo "${localstatedir}" | sed "s#NONE#${prefix}#" | sed "s#NONE#${ac_default_prefix}#"`
+full_libdir=`eval eval eval eval eval echo "${libdir}" | sed "s#NONE#${prefix}#" | sed "s#NONE#${ac_default_prefix}#"`
+default_softhsm2_conf="`eval echo ${full_sysconfdir} | sed s,NONE,$ac_default_prefix,g`/softhsm2.conf"
+softhsmtokendir=${full_localstatedir}/lib/softhsm/tokens/
+
+# Install the library in a sub-directory
+full_libdir="$full_libdir/softhsm"
+libdir=$full_libdir
+default_softhsm2_lib="$full_libdir/libsofthsm2.so"
+
+# For getConfigPath()
+AC_CHECK_FUNCS([getpwuid_r])
+
+# Define some variables for the code
+AC_DEFINE_UNQUOTED(
+       [VERSION_MAJOR],
+       [SOFTHSM_VERSION_MAJOR],
+       [SoftHSM major version number via PKCS#11]
+)
+AC_DEFINE_UNQUOTED(
+       [VERSION_MINOR],
+       [SOFTHSM_VERSION_MINOR],
+       [SoftHSM minor version number via PKCS#11]
+)
+AC_DEFINE_UNQUOTED(
+       [MAX_PIN_LEN],
+       [255],
+       [Maximum PIN length]
+)
+AC_DEFINE_UNQUOTED(
+       [MIN_PIN_LEN],
+       [4],
+       [Minimum PIN length]
+)
+AC_DEFINE_UNQUOTED(
+       [DEFAULT_SOFTHSM2_CONF],
+       ["$default_softhsm2_conf"],
+       [The default location of softhsm2.conf]
+)
+AC_DEFINE_UNQUOTED(
+       [DEFAULT_TOKENDIR],
+       ["$softhsmtokendir"],
+       [The default location of the token directory]
+)
+AC_DEFINE_UNQUOTED(
+       [DEFAULT_OBJECTSTORE_BACKEND],
+       ["file"],
+       [Default storage backend for token objects]
+)
+AC_DEFINE_UNQUOTED(
+       [DEFAULT_LOG_LEVEL],
+       ["INFO"],
+       [The default log level]
+)
+AC_DEFINE_UNQUOTED(
+       [DEFAULT_PKCS11_LIB],
+       ["$default_softhsm2_lib"],
+       [The default PKCS#11 library]
+)
+
+AC_SUBST([softhsmtokendir])
+AC_SUBST([default_softhsm2_conf])
+AC_SUBST([default_softhsm2_lib])
+
+# Generate the libtool script and install script
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+# Generate the makefiles
+AC_CONFIG_FILES([
+       Makefile
+       softhsm2.module
+       src/Makefile
+       src/lib/Makefile
+       src/lib/common/Makefile
+       src/lib/common/softhsm2.conf
+       src/lib/common/softhsm2.conf.5
+       src/lib/crypto/Makefile
+       src/lib/crypto/test/Makefile
+       src/lib/data_mgr/Makefile
+       src/lib/data_mgr/test/Makefile
+       src/lib/object_store/Makefile
+       src/lib/object_store/test/Makefile
+       src/lib/session_mgr/Makefile
+       src/lib/session_mgr/test/Makefile
+       src/lib/slot_mgr/Makefile
+       src/lib/slot_mgr/test/Makefile
+       src/lib/handle_mgr/Makefile
+       src/lib/handle_mgr/test/Makefile
+       src/lib/test/Makefile
+       src/lib/test/softhsm2.conf
+       src/lib/test/softhsm2-alt.conf
+       src/lib/test/tokens/dummy
+       src/bin/Makefile
+       src/bin/common/Makefile
+       src/bin/dump/Makefile
+       src/bin/keyconv/Makefile
+       src/bin/migrate/Makefile
+       src/bin/util/Makefile
+])
+
+AC_OUTPUT
diff --git a/SoftHSMv2/m4/acx_64bit.m4 b/SoftHSMv2/m4/acx_64bit.m4
new file mode 100644 (file)
index 0000000..f610b21
--- /dev/null
@@ -0,0 +1,29 @@
+AC_DEFUN([ACX_64BIT],[
+       AC_ARG_ENABLE(
+               [64bit],
+               [AS_HELP_STRING([--enable-64bit],[enable 64-bit compiling @<:@disabled@:>@])],
+               [enable_64bit="${enableval}"],
+               [enable_64bit="no"])
+
+       if test "x$enable_64bit" = "xyes"
+       then
+               AC_MSG_CHECKING(if we can compile in 64-bit mode)
+               tmp_CFLAGS=$CFLAGS
+               CFLAGS="-m64"
+               AC_RUN_IFELSE(
+                       [
+                               AC_LANG_PROGRAM([],[return sizeof(void*) == 8 ? 0 : 1;])
+                       ], [
+                               AC_MSG_RESULT(yes)
+                               CXXFLAGS="-m64 $CXXFLAGS"
+                               LDFLAGS="-m64 $LDFLAGS"
+                               CFLAGS="-m64 $tmp_CFLAGS"
+                       ],[
+                               AC_MSG_RESULT(no)
+                               AC_MSG_ERROR([Don't know how to compile in 64-bit mode.])
+                               CFLAGS=$tmp_CFLAGS
+                       ]
+               )
+       fi
+
+])
diff --git a/SoftHSMv2/m4/acx_botan.m4 b/SoftHSMv2/m4/acx_botan.m4
new file mode 100644 (file)
index 0000000..ed93786
--- /dev/null
@@ -0,0 +1,72 @@
+AC_DEFUN([ACX_BOTAN],[
+       AC_ARG_WITH(botan,
+               AC_HELP_STRING([--with-botan=PATH],[Specify prefix of path of Botan]),
+               [
+                       BOTAN_PATH="$withval"
+               ],
+               [
+                       BOTAN_PATH="/usr/local"
+               ])
+
+       BOTAN_VERSION_MAJOR=2
+       BOTAN_VERSION_MINOR=0
+       AC_CHECK_FILE($BOTAN_PATH/include/botan-2/botan/version.h,
+                     BOTAN_VERSION_MAJOR=2
+                     BOTAN_VERSION_MINOR=0,
+                     AC_CHECK_FILE($BOTAN_PATH/include/botan-1.11/botan/version.h,
+                                   BOTAN_VERSION_MAJOR=1
+                                   BOTAN_VERSION_MINOR=11,
+                                   AC_CHECK_FILE($BOTAN_PATH/include/botan-1.10/botan/version.h,
+                                                 BOTAN_VERSION_MAJOR=1
+                                                 BOTAN_VERSION_MINOR=10,
+                                                 AC_MSG_ERROR([Cannot find Botan includes]))))
+       AC_MSG_CHECKING(what are the Botan includes)
+       if test "x${BOTAN_VERSION_MAJOR}" = "x2"; then
+               BOTAN_INCLUDES="-I$BOTAN_PATH/include/botan-2"
+       else
+               BOTAN_INCLUDES="-I$BOTAN_PATH/include/botan-1.$BOTAN_VERSION_MINOR"
+       fi
+       AC_MSG_RESULT($BOTAN_INCLUDES)
+
+       AC_MSG_CHECKING(what are the Botan libs)
+       if test "x${BOTAN_VERSION_MAJOR}" = "x2"; then
+               BOTAN_LIBS="-L$BOTAN_PATH/lib -lbotan-2"
+       else
+               BOTAN_LIBS="-L$BOTAN_PATH/lib -lbotan-1.$BOTAN_VERSION_MINOR"
+       fi
+       AC_MSG_RESULT($BOTAN_LIBS)
+
+       if test "x${BOTAN_VERSION_MAJOR}" != "x1" -o "x${BOTAN_VERSION_MINOR}" != "x10"; then
+               AX_CXX_COMPILE_STDCXX_11([noext],[mandatory])
+       fi
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $BOTAN_INCLUDES"
+       LIBS="$LIBS $BOTAN_LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_LINK_IFELSE(
+               [AC_LANG_PROGRAM(
+                       [#include <botan/init.h>
+                       #include <botan/version.h>],
+                       [using namespace Botan;
+                       LibraryInitializer::initialize();
+                       #if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR($1,$2,$3)
+                       #error "Botan version too old";
+                       #endif])],
+               [AC_MSG_RESULT([checking for Botan >= v$1.$2.$3 ... yes])],
+               [AC_MSG_RESULT([checking for Botan >= v$1.$2.$3 ... no])
+                AC_MSG_ERROR([Missing the correct version of the Botan library])]
+       )
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+
+       AC_SUBST(BOTAN_INCLUDES)
+       AC_SUBST(BOTAN_LIBS)
+       AC_SUBST(BOTAN_VERSION_MAJOR)
+       AC_SUBST(BOTAN_VERSION_MINOR)
+])
diff --git a/SoftHSMv2/m4/acx_botan_aes_gcm.m4 b/SoftHSMv2/m4/acx_botan_aes_gcm.m4
new file mode 100644 (file)
index 0000000..d52c9cb
--- /dev/null
@@ -0,0 +1,37 @@
+AC_DEFUN([ACX_BOTAN_AES_GCM],[
+       AC_MSG_CHECKING(for Botan AES GCM support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <botan/botan.h>
+                       #include <botan/version.h>
+                       int main()
+                       {
+                               using namespace Botan;
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+                               return 0;
+#endif
+                               return 1;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found AES GCM])
+               AC_DEFINE([WITH_AES_GCM], [1],
+                         [Compile with AES GCM])
+       ],[
+               AC_MSG_RESULT([Cannot find AES GCM support, upgrade to Botan >= v2.0.0])
+
+       ])
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_botan_ecc.m4 b/SoftHSMv2/m4/acx_botan_ecc.m4
new file mode 100644 (file)
index 0000000..9bce21d
--- /dev/null
@@ -0,0 +1,51 @@
+AC_DEFUN([ACX_BOTAN_ECC],[
+       AC_MSG_CHECKING(for Botan ECC support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <botan/init.h>
+                       #include <botan/ec_group.h>
+                       #include <botan/oids.h>
+                       #include <botan/version.h>
+                       int main()
+                       {
+                               Botan::LibraryInitializer::initialize();
+                               const std::string name("secp256r1");
+                               const Botan::OID oid(Botan::OIDS::lookup(name));
+                               const Botan::EC_Group ecg(oid);
+                               try {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+                                       const std::vector<Botan::byte> der =
+                                           ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#else
+                                       const Botan::SecureVector<Botan::byte> der =
+                                           ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#endif
+                               } catch(...) {
+                                       return 1;
+                               }
+                               return 0;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found P256])
+       ],[
+               AC_MSG_RESULT([Cannot find P256])
+               AC_MSG_ERROR([
+Botan library has no valid ECC support. Please upgrade to a later version
+of Botan, above or including version 1.10.6 or 1.11.5.
+Alternatively disable ECC support in SoftHSM with --disable-ecc
+])
+       ],[])
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_botan_gnump.m4 b/SoftHSMv2/m4/acx_botan_gnump.m4
new file mode 100644 (file)
index 0000000..d15859a
--- /dev/null
@@ -0,0 +1,27 @@
+AC_DEFUN([ACX_BOTAN_GNUMP],[
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $BOTAN_INCLUDES"
+       LIBS="$LIBS $BOTAN_LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_LINK_IFELSE(
+               [AC_LANG_PROGRAM(
+                       [#include <botan/build.h>],
+                       [#ifndef BOTAN_HAS_ENGINE_GNU_MP
+                       #error "No GNU MP support";
+                       #endif])],
+               [AC_MSG_RESULT([checking for Botan GNU MP support... yes])],
+               [AC_MSG_RESULT([checking for Botan GNU MP support... no])
+                AC_MSG_WARN([
+====================================================
+Botan has not been built with GNU MP (--with-gnump).
+This will give negative impact on the performance.
+====================================================])]
+       )
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_botan_gost.m4 b/SoftHSMv2/m4/acx_botan_gost.m4
new file mode 100644 (file)
index 0000000..3720f4a
--- /dev/null
@@ -0,0 +1,52 @@
+AC_DEFUN([ACX_BOTAN_GOST],[
+       AC_MSG_CHECKING(for Botan GOST support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <botan/init.h>
+                       #include <botan/gost_3410.h>
+                       #include <botan/oids.h>
+                       #include <botan/version.h>
+                       int main()
+                       {
+                               Botan::LibraryInitializer::initialize();
+                               const std::string name("gost_256A");
+                               const Botan::OID oid(Botan::OIDS::lookup(name));
+                               const Botan::EC_Group ecg(oid);
+                               try {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+                                       const std::vector<Botan::byte> der =
+                                           ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#else
+                                       const Botan::SecureVector<Botan::byte> der =
+                                           ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#endif
+                               } catch(...) {
+                                       return 1;
+                               }
+
+                               return 0;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found GOST])
+       ],[
+               AC_MSG_RESULT([Cannot find GOST])
+               AC_MSG_ERROR([
+Botan library has no valid GOST support. Please upgrade to a later version
+of Botan, above or including version 1.10.6 or 1.11.5.
+Alternatively disable GOST support in SoftHSM with --disable-gost
+])
+       ],[])
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_botan_rawpss.m4 b/SoftHSMv2/m4/acx_botan_rawpss.m4
new file mode 100644 (file)
index 0000000..018e324
--- /dev/null
@@ -0,0 +1,37 @@
+AC_DEFUN([ACX_BOTAN_RAWPSS],[
+       AC_MSG_CHECKING(for Botan raw PSS support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C++])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <botan/botan.h>
+                       #include <botan/version.h>
+                       int main()
+                       {
+                               using namespace Botan;
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,3,0)
+                               return 0;
+#endif
+                               return 1;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found raw PSS])
+               AC_DEFINE([WITH_RAW_PSS], [1],
+                         [Compile with raw RSA PKCS PSS])
+       ],[
+               AC_MSG_RESULT([Cannot find raw PSS support, upgrade to Botan >= v2.3.0])
+
+       ])
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_botan_rfc5649.m4 b/SoftHSMv2/m4/acx_botan_rfc5649.m4
new file mode 100644 (file)
index 0000000..25a3d26
--- /dev/null
@@ -0,0 +1,47 @@
+AC_DEFUN([ACX_BOTAN_RFC5649],[
+       AC_MSG_CHECKING(for Botan RFC5649 support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_DEFINE([HAVE_AES_KEY_WRAP], [1],
+                 [Define if advanced AES key wrap without pad is supported])
+       AC_LANG_PUSH([C++])
+       AC_LINK_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <botan/botan.h>
+                       #include <botan/rfc3394.h>
+                       #include <botan/version.h>
+                       int main()
+                       {
+                               using namespace Botan;
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+                               secure_vector<byte> key(10);
+                               SymmetricKey kek("AABB");
+                               secure_vector<byte> x = rfc5649_keywrap(key, kek);
+#else
+                               SecureVector<byte> key(10);
+                               SymmetricKey kek("AABB");
+                               Algorithm_Factory& af = global_state().algorithm_factory();
+                               SecureVector<byte> x = rfc5649_keywrap(key, kek, af);
+#endif
+                               return 1;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found AES key wrap with pad])
+               AC_DEFINE([HAVE_AES_KEY_WRAP_PAD], [1],
+                         [Define if advanced AES key wrap with pad is supported])
+       ],[
+               AC_MSG_RESULT([Cannot find AES key wrap with pad])
+
+       ])
+       AC_LANG_POP([C++])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_cppunit.m4 b/SoftHSMv2/m4/acx_cppunit.m4
new file mode 100644 (file)
index 0000000..2720d81
--- /dev/null
@@ -0,0 +1,21 @@
+AC_DEFUN([ACX_CPPUNIT],[
+       AC_PATH_PROG([CPPUNIT_CONFIG], [cppunit-config])
+       AC_PATH_PROG([PKG_CONFIG], [pkg-config])
+       if test -n "${CPPUNIT_CONFIG}"; then
+               AC_MSG_CHECKING([cppunit cflags])
+               CPPUNIT_CFLAGS=`${CPPUNIT_CONFIG} --cflags`
+               AC_MSG_RESULT([${CPPUNIT_CFLAGS}])
+               AC_MSG_CHECKING([cppunit libs])
+               CPPUNIT_LIBS=`${CPPUNIT_CONFIG} --libs`
+               AC_MSG_RESULT([${CPPUNIT_LIBS}])
+       elif test -n "${PKG_CONFIG}"; then
+               AC_MSG_CHECKING([cppunit cflags])
+               CPPUNIT_CFLAGS=`${PKG_CONFIG} cppunit --cflags`
+               AC_MSG_RESULT([${CPPUNIT_CFLAGS}])
+               AC_MSG_CHECKING([cppunit libs])
+               CPPUNIT_LIBS=`${PKG_CONFIG} cppunit --libs`
+               AC_MSG_RESULT([${CPPUNIT_LIBS}])
+       fi
+       AC_SUBST([CPPUNIT_CFLAGS])
+       AC_SUBST([CPPUNIT_LIBS])
+])
diff --git a/SoftHSMv2/m4/acx_crypto_backend.m4 b/SoftHSMv2/m4/acx_crypto_backend.m4
new file mode 100644 (file)
index 0000000..c860c89
--- /dev/null
@@ -0,0 +1,168 @@
+AC_DEFUN([ACX_CRYPTO_BACKEND],[
+
+       # First check if we want to support ECC and GOST
+
+       AC_ARG_ENABLE(ecc,
+               AC_HELP_STRING([--enable-ecc],
+                       [Enable support for ECC (default enabled)]
+               ),
+               [enable_ecc="${enableval}"],
+               [enable_ecc="yes"]
+       )
+       AC_MSG_CHECKING(for ECC support)
+       if test "x${enable_ecc}" = "xyes"; then
+               AC_MSG_RESULT(yes)
+               AC_DEFINE_UNQUOTED(
+                       [WITH_ECC],
+                       [],
+                       [Compile with ECC support]
+               )
+       else
+               AC_MSG_RESULT(no)
+       fi
+       AM_CONDITIONAL([WITH_ECC], [test "x${enable_ecc}" = "xyes"])
+
+       AC_ARG_ENABLE(gost,
+               AC_HELP_STRING([--enable-gost],
+                       [Enable support for GOST (default enabled)]
+               ),
+               [enable_gost="${enableval}"],
+               [enable_gost="yes"]
+       )
+       AC_MSG_CHECKING(for GOST support)
+       if test "x${enable_gost}" = "xyes"; then
+               AC_MSG_RESULT(yes)
+               AC_DEFINE_UNQUOTED(
+                       [WITH_GOST],
+                       [],
+                       [Compile with GOST support]
+               )
+       else
+               AC_MSG_RESULT(no)
+       fi
+       AM_CONDITIONAL([WITH_GOST], [test "x${enable_gost}" = "xyes"])
+
+       # Second check for the FIPS 140-2 mode
+
+       AC_ARG_ENABLE(fips,
+               AC_HELP_STRING([--enable-fips],
+                       [Enable support for FIPS 140-2 mode (default disabled)]
+               ),
+               [enable_fips="${enableval}"],
+               [enable_fips="no"]
+       )
+       AC_MSG_CHECKING(for FIPS 140-2 mode)
+       if test "x${enable_fips}" = "xyes"; then
+               AC_MSG_RESULT(yes)
+               AC_DEFINE_UNQUOTED(
+                       [WITH_FIPS],
+                       [],
+                       [Compile with FIPS 140-2 mode]
+               )
+       else
+               AC_MSG_RESULT(no)
+       fi
+       AM_CONDITIONAL([WITH_GOST], [test "x${enable_fips}" = "xyes"])
+
+       # Then check what crypto library we want to use
+
+       AC_ARG_WITH(crypto-backend,
+               AC_HELP_STRING([--with-crypto-backend],
+                       [Select crypto backend (openssl|botan)]
+               ),
+               [crypto_backend="${withval}"],
+               [crypto_backend="openssl"]
+       )
+
+       AC_MSG_CHECKING(for crypto backend)
+
+       if test "x${crypto_backend}" = "xopenssl"; then
+               AC_MSG_RESULT(OpenSSL)
+
+               if test "x${enable_fips}" = "xyes"; then
+                       ACX_OPENSSL(1,0,1)
+               else
+                       ACX_OPENSSL(1,0,0)
+               fi
+
+               CRYPTO_INCLUDES=$OPENSSL_INCLUDES
+               CRYPTO_LIBS=$OPENSSL_LIBS
+
+               if test "x${enable_ecc}" = "xyes"; then
+                       ACX_OPENSSL_ECC
+               fi
+
+               if test "x${enable_gost}" = "xyes"; then
+                       if test "x${enable_fips}" = "xyes"; then
+                               AC_MSG_ERROR([GOST is not FIPS approved])
+                       fi
+                       ACX_OPENSSL_GOST
+               fi
+
+               if test "x${enable_fips}" = "xyes"; then
+                       ACX_OPENSSL_FIPS
+               else
+                       ACX_OPENSSL_EVPAESWRAP
+               fi
+
+               AC_DEFINE_UNQUOTED(
+                       [WITH_RAW_PSS],
+                       [1],
+                       [Compile with raw RSA PKCS PSS]
+               )
+               AC_DEFINE_UNQUOTED(
+                       [WITH_AES_GCM],
+                       [1],
+                       [Compile with AES_GCM]
+               )
+               AC_DEFINE_UNQUOTED(
+                       [WITH_OPENSSL],
+                       [],
+                       [Compile with OpenSSL support]
+               )
+
+       elif test "x${crypto_backend}" = "xbotan"; then
+               AC_MSG_RESULT(Botan)
+
+               ACX_BOTAN(1,10,0)
+
+               CRYPTO_INCLUDES=$BOTAN_INCLUDES
+               CRYPTO_LIBS=$BOTAN_LIBS
+
+               if test "x${enable_ecc}" = "xyes"; then
+                       ACX_BOTAN_ECC
+               fi
+
+               if test "x${enable_fips}" = "xyes"; then
+                       AC_MSG_ERROR([Botan does not support FIPS 140-2 mode])
+               fi
+
+               if test "x${enable_gost}" = "xyes"; then
+                       ACX_BOTAN_GOST
+               fi
+
+               if test "x${BOTAN_VERSION_MAJOR}" = "x1" -a "x${BOTAN_VERSION_MINOR}" = "x10"; then
+                       ACX_BOTAN_GNUMP
+               fi
+
+               ACX_BOTAN_RFC5649
+               ACX_BOTAN_RAWPSS
+               ACX_BOTAN_AES_GCM
+
+               AC_DEFINE_UNQUOTED(
+                       [WITH_BOTAN],
+                       [],
+                       [Compile with Botan support]
+               )
+
+       else
+               AC_MSG_RESULT(Unknown)
+               AC_MSG_ERROR([Crypto backend ${crypto_backend} not supported. Use openssl or botan.])
+       fi
+
+       AC_SUBST(CRYPTO_INCLUDES)
+       AC_SUBST(CRYPTO_LIBS)
+       AM_CONDITIONAL([WITH_OPENSSL], [test "x${crypto_backend}" = "xopenssl"])
+       AM_CONDITIONAL([WITH_BOTAN], [test "x${crypto_backend}" = "xbotan"])
+
+])
diff --git a/SoftHSMv2/m4/acx_dlopen.m4 b/SoftHSMv2/m4/acx_dlopen.m4
new file mode 100644 (file)
index 0000000..2d67614
--- /dev/null
@@ -0,0 +1,15 @@
+AC_DEFUN([ACX_DLOPEN],[
+  AC_CHECK_FUNC(dlopen, [AC_DEFINE(HAVE_DLOPEN,1,[Define if you have dlopen])],
+  [
+    AC_CHECK_LIB([dl],[dlopen], 
+      [AC_DEFINE(HAVE_DLOPEN,1,[Define if you have dlopen])
+      LIBS="$LIBS -ldl"],
+      [AC_CHECK_FUNC(LoadLibrary, 
+        [if test $ac_cv_func_LoadLibrary = yes; then
+          AC_DEFINE(HAVE_LOADLIBRARY, 1, [Whether LoadLibrary is available])
+        fi
+        ], [AC_MSG_ERROR(No dynamic library loading support)]
+      )]
+    )
+  ])
+])
diff --git a/SoftHSMv2/m4/acx_non_paged_memory.m4 b/SoftHSMv2/m4/acx_non_paged_memory.m4
new file mode 100644 (file)
index 0000000..0253e98
--- /dev/null
@@ -0,0 +1,57 @@
+AC_DEFUN([ACX_NON_PAGED_MEMORY],[
+
+       AC_ARG_ENABLE(non-paged-memory,
+               AC_HELP_STRING([--disable-non-paged-memory],
+                       [Disable non-paged memory for secure storage (default enabled)]
+               ),
+               [enable_non_paged_memory="${enableval}"],
+               [enable_non_paged_memory="yes"]
+       )
+
+       AC_MSG_CHECKING(for non-paged memory for secure storage)
+
+       if test "x${enable_non_paged_memory}" = "xyes"; then
+               AC_MSG_RESULT(enabled)
+               AC_DEFINE_UNQUOTED(
+                       [SENSITIVE_NON_PAGE],
+                       [],
+                       [Non-paged memory for secure storage]
+               )
+               AC_CHECK_HEADERS([sys/mman.h])
+
+               AC_MSG_CHECKING(the maximum size that may be locked into memory)
+               MLOCK_SIZE="`ulimit -l`"
+               AC_MSG_RESULT($MLOCK_SIZE)
+
+               if test "x${MLOCK_SIZE}" != "xunlimited"; then
+                       AC_MSG_WARN([
+======================================================================
+SoftHSM has been configured to store sensitive data in non-page RAM
+(i.e. memory that is not swapped out to disk). This is the default and
+most secure configuration. Your system, however, is not configured to
+support this model in non-privileged accounts (i.e. user accounts).
+
+You can check the setting on your system by running the following
+command in a shell:
+
+       ulimit -l
+
+If this does not return "unlimited" and you plan to run SoftHSM from
+non-privileged accounts then you should edit the configuration file
+/etc/security/limits.conf (on most systems).
+
+You will need to add the following lines to this file:
+
+#<domain>      <type>          <item>          <value>
+*              -               memlock         unlimited
+
+Alternatively, you can elect to disable this feature of SoftHSM by
+re-running configure with the option "--disable-non-paged-memory". 
+Please be advised that this may seriously degrade the security of 
+SoftHSM.
+======================================================================])
+               fi
+       else
+               AC_MSG_RESULT(disabled)
+       fi
+])
diff --git a/SoftHSMv2/m4/acx_openssl.m4 b/SoftHSMv2/m4/acx_openssl.m4
new file mode 100644 (file)
index 0000000..e90c78f
--- /dev/null
@@ -0,0 +1,60 @@
+AC_DEFUN([ACX_OPENSSL],[
+       AC_ARG_WITH(openssl,
+               AC_HELP_STRING([--with-openssl=PATH],[Specify prefix of path of OpenSSL]),
+               [
+                       OPENSSL_PATH="$withval"
+               ],
+               [
+                       OPENSSL_PATH="/usr/local"
+               ])
+
+       AC_MSG_CHECKING(what are the OpenSSL includes)
+       OPENSSL_INCLUDES="-I$OPENSSL_PATH/include"
+       AC_MSG_RESULT($OPENSSL_INCLUDES)
+
+       AC_MSG_CHECKING(what are the OpenSSL libs)
+       OPENSSL_LIBS="-L$OPENSSL_PATH/lib -lcrypto"
+       AC_MSG_RESULT($OPENSSL_LIBS)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $OPENSSL_INCLUDES"
+       LIBS="$OPENSSL_LIBS $LIBS"
+
+       AC_CHECK_HEADERS([openssl/ssl.h],,[AC_MSG_ERROR([Can't find OpenSSL headers])])
+       AC_CHECK_LIB(crypto, BN_new,,[AC_MSG_ERROR([Can't find OpenSSL library])])
+
+       AC_MSG_CHECKING([for OpenSSL version])
+       CHECK_OPENSSL_VERSION=m4_format(0x%02x%02x%02x000L, $1, $2, $3)
+       AC_LANG_PUSH([C])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/ssl.h>
+                       #include <openssl/opensslv.h>
+                       int main()
+                       {
+                       #ifndef OPENSSL_VERSION_NUMBER
+                               return -1;
+                       #endif
+                       #if OPENSSL_VERSION_NUMBER >= $CHECK_OPENSSL_VERSION
+                               return 0;
+                       #else
+                               return 1;
+                       #endif
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([>= $1.$2.$3])
+       ],[
+               AC_MSG_RESULT([< $1.$2.$3])
+               AC_MSG_ERROR([OpenSSL library too old ($1.$2.$3 or later required)])
+       ],[])
+       AC_LANG_POP([C])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+
+       AC_SUBST(OPENSSL_INCLUDES)
+       AC_SUBST(OPENSSL_LIBS)
+])
diff --git a/SoftHSMv2/m4/acx_openssl_ecc.m4 b/SoftHSMv2/m4/acx_openssl_ecc.m4
new file mode 100644 (file)
index 0000000..612c505
--- /dev/null
@@ -0,0 +1,37 @@
+AC_DEFUN([ACX_OPENSSL_ECC],[
+       AC_MSG_CHECKING(for OpenSSL ECC support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/ecdsa.h>
+                       #include <openssl/objects.h>
+                       int main()
+                       {
+                               EC_KEY *ec256, *ec384, *ec521;
+
+                               ec256 = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+                               ec384 = EC_KEY_new_by_curve_name(NID_secp384r1);
+                               ec521 = EC_KEY_new_by_curve_name(NID_secp521r1);
+                               if (ec256 == NULL || ec384 == NULL || ec521 == NULL)
+                                       return 1;
+                               return 0;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found P256, P384, and P521])
+       ],[
+               AC_MSG_RESULT([Cannot find P256, P384, or P521])
+               AC_MSG_ERROR([OpenSSL library has no ECC support])
+       ],[])
+       AC_LANG_POP([C])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_openssl_fips.m4 b/SoftHSMv2/m4/acx_openssl_fips.m4
new file mode 100644 (file)
index 0000000..0491397
--- /dev/null
@@ -0,0 +1,50 @@
+AC_DEFUN([ACX_OPENSSL_FIPS],[
+       AC_MSG_CHECKING(for OpenSSL FIPS capable library)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       # check whether we can build an application which can
+       # "reference the OpenSSL FIPS object module"
+
+       AC_LANG_PUSH([C])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/crypto.h>
+                       int main()
+                       {
+                               return !FIPS_mode_set(1);
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found working FIPS_mode_set()])
+       ],[
+               AC_MSG_RESULT([FIPS_mode_set(1) failed])
+               AC_MSG_ERROR([OpenSSL library is not FIPS capable])
+       ],[])
+       AC_LANG_POP([C])
+
+       # build missing fips_premain_dso tool
+
+       if test "x${FIPSLD_CC}" != "x"; then
+               THERE="`echo $CC | sed -e 's|[[^/]]*$||'`"..
+               if test "x${FIPSLIBDIR}" != "x"; then
+                       PREMAIN_C="${FIPSLIBDIR}/fips_premain.c"
+               elif test -f "${THERE}/fips/fips_premain.c"; then
+                       PREMAIN_C="${THERE}/fips/fips_premain.c"
+               elif test -f "${THERE}/lib/fips_premain.c"; then
+                       PREMAIN_C="${THERE}/lib/fips_premain.c"
+               else
+                       AC_MSG_WARN([can't find fips_premain.c])
+               fi
+
+               $FIPSLD_CC $CPPFLAGS -DFINGERPRINT_PREMAIN_DSO_LOAD \
+               -o src/lib/fips_premain_dso $PREMAIN_C $LIBS
+       fi
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_openssl_gost.m4 b/SoftHSMv2/m4/acx_openssl_gost.m4
new file mode 100644 (file)
index 0000000..dca489b
--- /dev/null
@@ -0,0 +1,65 @@
+AC_DEFUN([ACX_OPENSSL_GOST],[
+       AC_MSG_CHECKING(for OpenSSL GOST support)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C])
+       AC_RUN_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/engine.h>
+                       #include <openssl/crypto.h>
+                       #include <openssl/opensslv.h>
+                       int main()
+                       {
+                               ENGINE* eg;
+                               const EVP_MD* EVP_GOST_34_11;
+
+                               /* Initialise OpenSSL */
+                               OpenSSL_add_all_algorithms();
+
+                               /* Load engines */
+                       #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+                               ENGINE_load_builtin_engines();
+                       #else
+                               OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN | OPENSSL_INIT_LOAD_CONFIG, NULL);
+                       #endif
+
+                               /* Initialise the GOST engine */
+                               eg = ENGINE_by_id("gost");
+                               if (eg == NULL)
+                                       return 1;
+                               if (ENGINE_init(eg) <= 0)
+                                       return 1;
+
+                               /* better than digest_gost */
+                               EVP_GOST_34_11 = ENGINE_get_digest(eg, NID_id_GostR3411_94);
+                               if (EVP_GOST_34_11 == NULL)
+                                       return 1;
+
+                               /* from the openssl.cnf */
+                               if (ENGINE_register_pkey_asn1_meths(eg) <= 0)
+                                       return 1;
+                               if (ENGINE_ctrl_cmd_string(eg,
+                                   "CRYPT_PARAMS",
+                                   "id-Gost28147-89-CryptoPro-A-ParamSet",
+                                   0) <= 0)
+                                       return 1;
+
+                               return 0;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([Found GOST engine])
+       ],[
+               AC_MSG_RESULT([Cannot find GOST engine])
+               AC_MSG_ERROR([OpenSSL library has no GOST support])
+       ],[])
+       AC_LANG_POP([C])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_openssl_rfc5649.m4 b/SoftHSMv2/m4/acx_openssl_rfc5649.m4
new file mode 100644 (file)
index 0000000..c68a336
--- /dev/null
@@ -0,0 +1,51 @@
+AC_DEFUN([ACX_OPENSSL_EVPAESWRAP],[
+       AC_MSG_CHECKING(OpenSSL EVP interface for AES key wrapping)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $CRYPTO_INCLUDES"
+       LIBS="$CRYPTO_LIBS $LIBS"
+
+       AC_LANG_PUSH([C])
+
+       AC_LINK_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/evp.h>
+                       int main()
+                       {
+                               EVP_aes_128_wrap();
+                               return 1;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([RFC 3394 is supported])
+               AC_DEFINE([HAVE_AES_KEY_WRAP], [1],
+                         [Define if advanced AES key wrap without pad is supported in EVP interface])
+       ],[
+               AC_MSG_RESULT([RFC 3394 is not supported])
+       ])
+
+       AC_MSG_CHECKING(OpenSSL EVP interface for AES key wrapping with pad)
+       AC_LINK_IFELSE([
+               AC_LANG_SOURCE([[
+                       #include <openssl/evp.h>
+                       int main()
+                       {
+                               EVP_aes_128_wrap_pad();
+                               return 1;
+                       }
+               ]])
+       ],[
+               AC_MSG_RESULT([RFC 5649 is supported])
+               AC_DEFINE([HAVE_AES_KEY_WRAP_PAD], [1],
+                         [Define if advanced AES key wrap with pad is supported in EVP interface])
+       ],[
+               AC_MSG_RESULT([RFC 5649 is not supported])
+       ])
+
+       AC_LANG_POP([C])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+])
diff --git a/SoftHSMv2/m4/acx_p11kit.m4 b/SoftHSMv2/m4/acx_p11kit.m4
new file mode 100644 (file)
index 0000000..20c7b7e
--- /dev/null
@@ -0,0 +1,36 @@
+AC_DEFUN([ACX_P11KIT],[
+       AC_ARG_ENABLE([p11-kit],
+               AC_HELP_STRING([--enable-p11-kit],
+                       [Enable p11-kit integration (default enabled)]
+               ),
+               [enable_p11kit="${enableval}"],
+               [enable_p11kit="yes"]
+       )
+
+       AC_ARG_WITH(p11-kit,
+               AC_HELP_STRING([--with-p11-kit=PATH],[Specify install path of the p11-kit module, will override path given by pkg-config]),
+               [P11KIT_PATH="$withval"],
+               [P11KIT_PATH=""]
+       )
+
+       AC_MSG_CHECKING(for p11-kit integration)
+       if test "x${enable_p11kit}" = "xyes"; then
+               AC_MSG_RESULT(yes)
+               if test "x${P11KIT_PATH}" = "x"; then
+                       AC_PATH_PROG(PKGCONFIG, [pkg-config])
+                       if test "x${PKGCONFIG}" != "x" && ${PKGCONFIG} --exists p11-kit-1; then
+                               P11KIT_PATH=`${PKGCONFIG} --variable=p11_module_configs p11-kit-1`
+                       fi
+               fi
+               AC_MSG_CHECKING(where to install the p11-kit module)
+               AC_MSG_RESULT($P11KIT_PATH)
+               if test "x${P11KIT_PATH}" = "x"; then
+                       AC_MSG_WARN([Missing install path for the p11-kit module, skipping module])
+               fi
+       else
+               AC_MSG_RESULT(no)
+       fi
+
+       AC_SUBST(P11KIT_PATH)
+       AM_CONDITIONAL([WITH_P11KIT], [test "x${enable_p11kit}" = "xyes" -a "x${P11KIT_PATH}" != "x"])
+])
diff --git a/SoftHSMv2/m4/acx_pedantic.m4 b/SoftHSMv2/m4/acx_pedantic.m4
new file mode 100644 (file)
index 0000000..11808ee
--- /dev/null
@@ -0,0 +1,12 @@
+AC_DEFUN([ACX_PEDANTIC],[
+       AC_ARG_ENABLE(
+               [pedantic],
+               [AS_HELP_STRING([--enable-pedantic],[enable pedantic compile mode @<:@enabled@:>@])],
+               ,
+               [enable_pedantic="yes"]
+       )
+       if test "${enable_pedantic}" = "yes"; then
+               enable_strict="yes";
+               CFLAGS="${CFLAGS} -pedantic"
+       fi
+])
diff --git a/SoftHSMv2/m4/acx_prefixhack.m4 b/SoftHSMv2/m4/acx_prefixhack.m4
new file mode 100644 (file)
index 0000000..16a50a2
--- /dev/null
@@ -0,0 +1,23 @@
+# Special processing of paths depending on whether --prefix,
+# --sysconfdir or --localstatedir arguments were given.
+
+AC_DEFUN([ACX_PREFIXHACK],[
+       case "$prefix" in
+               NONE)
+                       case "$sysconfdir" in
+                               '${prefix}/etc')
+                                       sysconfdir=/etc
+                                       ac_configure_args="$ac_configure_args --sysconfdir=$sysconfdir"
+                                       AC_MSG_NOTICE([sysconfdir set to $sysconfdir])
+                                       ;;
+                       esac
+                       case "$localstatedir" in
+                               '${prefix}/var')
+                                       localstatedir=/var
+                                       ac_configure_args="$ac_configure_args --localstatedir=$localstatedir"
+                                       AC_MSG_NOTICE([localstate set to $localstatedir])
+                                       ;;
+                       esac
+                       ;;
+       esac
+])
diff --git a/SoftHSMv2/m4/acx_sqlite3.m4 b/SoftHSMv2/m4/acx_sqlite3.m4
new file mode 100644 (file)
index 0000000..cf829b7
--- /dev/null
@@ -0,0 +1,40 @@
+AC_DEFUN([ACX_SQLITE3],[
+       AC_ARG_WITH(sqlite3,
+               AC_HELP_STRING([--with-sqlite3=PATH],[Specify prefix of path of SQLite3]),
+               [
+                       SQLITE3_PATH="$withval"
+                       AC_PATH_PROGS(SQLITE3, sqlite3, sqlite3, $withval/bin)
+                       
+               ],[
+                       SQLITE3_PATH="/usr/local"
+                       AC_PATH_PROGS(SQLITE3, sqlite3, sqlite3, $PATH)
+               ])
+
+       
+       if ! test -x "$SQLITE3"; then
+               AC_MSG_ERROR([sqlite3 command not found])
+       fi
+       
+       AC_MSG_CHECKING(what are the SQLite3 includes)
+       SQLITE3_INCLUDES="-I$SQLITE3_PATH/include"
+       AC_MSG_RESULT($SQLITE3_INCLUDES)
+
+       AC_MSG_CHECKING(what are the SQLite3 libs)
+       SQLITE3_LIBS="-L$SQLITE3_PATH/lib -lsqlite3"
+       AC_MSG_RESULT($SQLITE3_LIBS)
+
+       tmp_CPPFLAGS=$CPPFLAGS
+       tmp_LIBS=$LIBS
+
+       CPPFLAGS="$CPPFLAGS $SQLITE3_INCLUDES"
+       LIBS="$LIBS $SQLITE3_LIBS"
+
+       AC_CHECK_HEADERS(sqlite3.h,,[AC_MSG_ERROR([Can't find SQLite3 headers])])
+       AC_CHECK_LIB(sqlite3, sqlite3_prepare_v2, [], [AC_MSG_ERROR([Missing SQLite3 library v3.4.2 or greater])])
+
+       CPPFLAGS=$tmp_CPPFLAGS
+       LIBS=$tmp_LIBS
+
+       AC_SUBST(SQLITE3_INCLUDES)
+       AC_SUBST(SQLITE3_LIBS)
+])
diff --git a/SoftHSMv2/m4/acx_strict.m4 b/SoftHSMv2/m4/acx_strict.m4
new file mode 100644 (file)
index 0000000..0bb8089
--- /dev/null
@@ -0,0 +1,12 @@
+AC_DEFUN([ACX_STRICT],[
+       AC_ARG_ENABLE(
+               [strict],
+               [AS_HELP_STRING([--enable-strict],[enable strict compile mode @<:@enabled@:>@])],
+               ,
+               [enable_strict="yes"]
+       )
+       if test "${enable_strict}" = "yes"; then
+               CFLAGS="${CFLAGS} -Wall -Wextra"
+               CXXFLAGS="${CXXFLAGS} -Wall -Wextra"
+       fi
+])
diff --git a/SoftHSMv2/m4/acx_visibility.m4 b/SoftHSMv2/m4/acx_visibility.m4
new file mode 100644 (file)
index 0000000..589a72e
--- /dev/null
@@ -0,0 +1,14 @@
+AC_DEFUN([ACX_VISIBILITY],[
+       AC_ARG_ENABLE(
+               [visibility],
+               [AS_HELP_STRING([--disable-visibility],[disable hidden visibilty link mode @<:@enabled@:>@])],
+               [enable_visibility="${enableval}"],
+               [enable_visibility="yes"]
+       )
+       if test "${enable_visibility}" = "yes"; then
+               CFLAGS="${CFLAGS} -fvisibility=hidden"
+               CXXFLAGS="${CXXFLAGS} -fvisibility=hidden"
+               AC_DEFINE(CRYPTOKI_VISIBILITY, 1,
+                         [Define to default visibility of PKCS@%:@11 entry points])
+       fi
+])
diff --git a/SoftHSMv2/m4/acx_yield.m4 b/SoftHSMv2/m4/acx_yield.m4
new file mode 100644 (file)
index 0000000..335c190
--- /dev/null
@@ -0,0 +1,10 @@
+AC_DEFUN([ACX_YIELD],[
+       YIELD_LIB=
+       # Solaris has sched_yield in librt, not in libpthread or libc.
+       # Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt.
+       AC_CHECK_LIB(rt, sched_yield, [YIELD_LIB=-lrt],
+               [AC_CHECK_LIB(posix4, sched_yield, [YIELD_LIB=-lposix4])])
+       AC_SUBST([YIELD_LIB])
+
+       AC_CHECK_HEADER([sched.h])
+])
diff --git a/SoftHSMv2/m4/ax_cxx_compile_stdcxx_11.m4 b/SoftHSMv2/m4/ax_cxx_compile_stdcxx_11.m4
new file mode 100644 (file)
index 0000000..28ab4eb
--- /dev/null
@@ -0,0 +1,146 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+#   The first argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The second argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline C++11 support is required and that the macro
+#   should error out if no mode with that support is found.  If specified
+#   'optional', then configuration proceeds regardless, after defining
+#   HAVE_CXX11 if and only if a supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014 Alexey Sokolov <sokolov@google.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 4
+
+m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
+  #include <memory>
+
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    struct Base {
+    virtual void f() {}
+    };
+    struct Child : public Base {
+    virtual void f() override {}
+    };
+
+    std::unique_ptr<Base> ptr_to_base;
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+    auto l = [](){};
+]])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+  m4_if([$1], [], [],
+        [$1], [ext], [],
+        [$1], [noext], [],
+        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+  ax_cv_cxx_compile_cxx11,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+    [ax_cv_cxx_compile_cxx11=yes],
+    [ax_cv_cxx_compile_cxx11=no])])
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$1], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++11 -std=gnu++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$1], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=c++11 -std=c++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX11=0
+      AC_MSG_NOTICE([No compiler with C++11 support was found])
+    else
+      HAVE_CXX11=1
+      AC_DEFINE(HAVE_CXX11,1,
+                [define if the compiler supports basic C++11 syntax])
+    fi
+
+    AC_SUBST(HAVE_CXX11)
+  fi
+])
diff --git a/SoftHSMv2/prepdist.sh b/SoftHSMv2/prepdist.sh
new file mode 100644 (file)
index 0000000..93e5cb2
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+PREFIX=/tmp/softhsm2-release
+export LD_LIBRARY_PATH=/usr/local/lib
+
+if [ ! -f autogen.sh -a ! -f configure ]; then
+        echo "Unable to continue, no autogen.sh or configure"
+        exit 1
+fi
+
+if [ -f autogen.sh ]; then 
+        sh autogen.sh 
+fi &&
+mkdir -p build &&
+cd build &&
+../configure --prefix=${PREFIX} \
+       --with-crypto-backend=botan \
+       --with-botan=/usr/local \
+       $@
diff --git a/SoftHSMv2/softhsm2.module.in b/SoftHSMv2/softhsm2.module.in
new file mode 100644 (file)
index 0000000..fe88908
--- /dev/null
@@ -0,0 +1,4 @@
+# This file describes how to load the pk11 module
+# See: http://p11-glue.freedesktop.org/doc/p11-kit/config.html
+
+module: @default_softhsm2_lib@
diff --git a/SoftHSMv2/src/Makefile.am b/SoftHSMv2/src/Makefile.am
new file mode 100644 (file)
index 0000000..7f51142
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+SUBDIRS = lib bin
diff --git a/SoftHSMv2/src/bin/Makefile.am b/SoftHSMv2/src/bin/Makefile.am
new file mode 100644 (file)
index 0000000..354c272
--- /dev/null
@@ -0,0 +1,10 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+SUBDIRS = common keyconv util dump
+
+if BUILD_MIGRATE
+SUBDIRS += migrate
+endif
+
+EXTRA_DIST =   $(srcdir)/win32/*.cpp \
+               $(srcdir)/win32/*.h
diff --git a/SoftHSMv2/src/bin/common/Makefile.am b/SoftHSMv2/src/bin/common/Makefile.am
new file mode 100644 (file)
index 0000000..e3a2b24
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+EXTRA_DIST =           $(srcdir)/*.h
diff --git a/SoftHSMv2/src/bin/common/findslot.cpp b/SoftHSMv2/src/bin/common/findslot.cpp
new file mode 100644 (file)
index 0000000..5936db7
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+/*****************************************************************************
+ findslot.cpp
+
+ Helper function to find the slot
+ *****************************************************************************/
+
+#include <config.h>
+#include "findslot.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern CK_FUNCTION_LIST_PTR p11;
+
+// Find the slot/token
+int findSlot(char* slot, char* serial, char* token, bool freeToken, CK_SLOT_ID& slotID)
+{
+       if (slot != NULL)
+       {
+               int slotNumber = atoi(slot);
+               if (slotNumber < 0)
+               {
+                       fprintf(stderr, "ERROR: The slot number is negative.\n");
+                       return 1;
+               }
+
+               slotID = slotNumber;
+               return 0;
+       }
+
+       if (serial == NULL && token == NULL && freeToken == false)
+       {
+               fprintf(stderr, "ERROR: A slot/token must be supplied. "
+                               "Use --slot <number>, --serial <serial>, "
+                               "--token <label>, or --free\n");
+               return 1;
+       }
+
+       // Load the variables
+       CK_UTF8CHAR paddedSerial[16];
+       CK_UTF8CHAR paddedToken[32];
+       if (serial != NULL)
+       {
+               size_t inSize = strlen(serial);
+               size_t outSize = sizeof(paddedSerial);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --serial is too long.\n");
+                       return 1;
+               }
+               memset(paddedSerial, ' ', outSize);
+               memcpy(paddedSerial, serial, inSize);
+       }
+       if (token != NULL)
+       {
+               size_t inSize = strlen(token);
+               size_t outSize = sizeof(paddedToken);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --token is too long.\n");
+                       return 1;
+               }
+               memset(paddedToken, ' ', outSize);
+               memcpy(paddedToken, token, inSize);
+       }
+
+       CK_ULONG ulSlotCount;
+       CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the number of slots.\n");
+               return 1;
+       }
+
+       CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
+       if (pSlotList == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+               return 1;
+       }
+
+       rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the slot list.\n");
+               free(pSlotList);
+               return 1;
+       }
+
+       size_t counter = 0;
+       for (CK_ULONG i = 0; i < ulSlotCount; i++)
+       {
+               CK_TOKEN_INFO tokenInfo;
+
+               rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo);
+               if (rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n",
+                               pSlotList[i]);
+                       free(pSlotList);
+                       return 1;
+               }
+
+               if (freeToken)
+               {
+                       if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0)
+                       {
+                               printf("Slot %lu has a free/uninitialized token.\n", pSlotList[i]);
+                               slotID = pSlotList[i];
+                               free(pSlotList);
+                               return 0;
+                       }
+               }
+               else
+               {
+                       if (serial != NULL && token == NULL &&
+                               memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0)
+                       {
+                               printf("Found slot %lu with matching serial.\n",
+                                      pSlotList[i]);
+                               slotID = pSlotList[i];
+                               counter++;
+                       }
+                       if (serial == NULL && token != NULL &&
+                               memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0)
+                       {
+                               printf("Found slot %lu with matching token label.\n",
+                                      pSlotList[i]);
+                               slotID = pSlotList[i];
+                               counter++;
+                       }
+                       if (serial != NULL && token != NULL &&
+                               memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0 &&
+                               memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0)
+                       {
+                               printf("Found slot %lu with matching serial and token label.\n",
+                                      pSlotList[i]);
+                               slotID = pSlotList[i];
+                               counter++;
+                       }
+               }
+       }
+
+       free(pSlotList);
+
+       if (counter == 1) return 0;
+       if (counter > 1)
+       {
+               fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n");
+               return 1;
+       }
+
+       fprintf(stderr, "ERROR: Could not find a slot/token using --serial, --token, or --free.\n");
+       return 1;
+}
+
+// Find the slot/token
+int findSlot(char* slot, char* serial, char* token, CK_SLOT_ID& slotID)
+{
+       if (slot != NULL)
+       {
+               int slotNumber = atoi(slot);
+               if (slotNumber < 0)
+               {
+                       fprintf(stderr, "ERROR: The slot number is negative.\n");
+                       return 1;
+               }
+
+               slotID = slotNumber;
+               return 0;
+       }
+
+       if (serial == NULL && token == NULL)
+       {
+               fprintf(stderr, "ERROR: A slot/token must be supplied. "
+                               "Use --slot <number>, --serial <serial>, "
+                               "or --token <label>\n");
+               return 1;
+       }
+
+       // Load the variables
+       CK_UTF8CHAR paddedSerial[16];
+       CK_UTF8CHAR paddedToken[32];
+       if (serial != NULL)
+       {
+               size_t inSize = strlen(serial);
+               size_t outSize = sizeof(paddedSerial);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --serial is too long.\n");
+                       return 1;
+               }
+               memset(paddedSerial, ' ', outSize);
+               memcpy(paddedSerial, serial, inSize);
+       }
+       if (token != NULL)
+       {
+               size_t inSize = strlen(token);
+               size_t outSize = sizeof(paddedToken);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --token is too long.\n");
+                       return 1;
+               }
+               memset(paddedToken, ' ', outSize);
+               memcpy(paddedToken, token, inSize);
+       }
+
+       CK_ULONG ulSlotCount;
+       CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the number of slots.\n");
+               return 1;
+       }
+
+       CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
+       if (pSlotList == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+               return 1;
+       }
+
+       rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the slot list.\n");
+               free(pSlotList);
+               return 1;
+       }
+
+       size_t counter = 0;
+       for (CK_ULONG i = 0; i < ulSlotCount; i++)
+       {
+               CK_TOKEN_INFO tokenInfo;
+
+               rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo);
+               if (rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n",
+                               pSlotList[i]);
+                       free(pSlotList);
+                       return 1;
+               }
+
+               if (serial != NULL && token == NULL &&
+                       memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0)
+               {
+                       printf("Found slot %lu with matching serial.\n",
+                              pSlotList[i]);
+                       slotID = pSlotList[i];
+                       counter++;
+               }
+               if (serial == NULL && token != NULL &&
+                       memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0)
+               {
+                       printf("Found slot %lu with matching token label.\n",
+                              pSlotList[i]);
+                       slotID = pSlotList[i];
+                       counter++;
+               }
+               if (serial != NULL && token != NULL &&
+                       memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0 &&
+                       memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0)
+               {
+                       printf("Found slot %lu with matching serial and token label.\n",
+                              pSlotList[i]);
+                       slotID = pSlotList[i];
+                       counter++;
+               }
+       }
+
+       free(pSlotList);
+
+       if (counter == 1) return 0;
+       if (counter > 1)
+       {
+               fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n");
+               return 1;
+       }
+
+       fprintf(stderr, "ERROR: Could not find a slot/token using --serial, or --token\n");
+       return 1;
+}
+
+// Find the slot/token
+int findSlot(CK_TOKEN_INFO tokenInfo, CK_SLOT_ID& slotID)
+{
+       CK_ULONG ulSlotCount;
+       CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the number of slots.\n");
+               return 1;
+       }
+
+       CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
+       if (pSlotList == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+               return 1;
+       }
+
+       rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the slot list.\n");
+               free(pSlotList);
+               return 1;
+       }
+
+       size_t counter = 0;
+       for (CK_ULONG i = 0; i < ulSlotCount; i++)
+       {
+               CK_TOKEN_INFO currentTokenInfo;
+
+               rv = p11->C_GetTokenInfo(pSlotList[i], &currentTokenInfo);
+               if (rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n",
+                               pSlotList[i]);
+                       free(pSlotList);
+                       return 1;
+               }
+
+               if (memcmp(currentTokenInfo.serialNumber, tokenInfo.serialNumber, sizeof(tokenInfo.serialNumber)) == 0 &&
+                   memcmp(currentTokenInfo.label, tokenInfo.label, sizeof(tokenInfo.label)) == 0)
+               {
+                       slotID = pSlotList[i];
+                       counter++;
+               }
+       }
+
+       free(pSlotList);
+
+       if (counter == 1) return 0;
+       if (counter > 1)
+       {
+               fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n");
+               return 1;
+       }
+
+       fprintf(stderr, "ERROR: Could not find a slot/token using --serial, or --token\n");
+       return 1;
+}
diff --git a/SoftHSMv2/src/bin/common/findslot.h b/SoftHSMv2/src/bin/common/findslot.h
new file mode 100644 (file)
index 0000000..f8a7ba6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+/*****************************************************************************
+ findslot.h
+
+ Helper function to find the slot number
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BIN_FINDSLOT_H
+#define _SOFTHSM_V2_BIN_FINDSLOT_H
+
+#include "cryptoki.h"
+
+int findSlot(char* slot, char* serial, char* token, bool freeToken, CK_SLOT_ID& slotID);
+int findSlot(char* slot, char* serial, char* token, CK_SLOT_ID& slotID);
+int findSlot(CK_TOKEN_INFO tokenInfo, CK_SLOT_ID& slotID);
+
+#endif // !_SOFTHSM_V2_BIN_FINDSLOT_H
diff --git a/SoftHSMv2/src/bin/common/getpw.cpp b/SoftHSMv2/src/bin/common/getpw.cpp
new file mode 100644 (file)
index 0000000..938abd5
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ getpw.cpp
+
+ Helper function to get a password from the user
+ *****************************************************************************/
+
+#include <config.h>
+#include "getpw.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <termios.h>
+#include <signal.h>
+#endif
+
+#ifndef _WIN32
+// Remember the signal number
+static volatile sig_atomic_t signo;
+
+void sighandler(int s)
+{
+       signo = s;
+}
+#endif
+
+int getpin(const char* prompt, char* buffer, size_t size)
+{
+       if (prompt == NULL || buffer == NULL || size < 1)
+               return -1;
+
+       printf("%s", prompt);
+
+#ifdef _WIN32
+       HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
+       DWORD mode;
+
+       // Save current console mode
+       if (!GetConsoleMode(hstdin, &mode))
+               return -1;
+
+       // Update the console mode
+       if (hstdin == INVALID_HANDLE_VALUE || !(SetConsoleMode(hstdin, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)))
+               return -1;
+#else
+       struct termios new_attr, old_attr;
+
+       // Get current terminal attributes
+       if (tcgetattr(STDIN_FILENO, &old_attr) < 0)
+               return -1;
+
+       // Save the mode flags
+       new_attr = old_attr;
+
+       // Update the mode flags
+       new_attr.c_lflag &= ~ICANON;
+       new_attr.c_lflag &= ~ECHO;
+
+       // Handle the SIGINT signal
+       signo = 0;
+       struct sigaction osa, sa;
+       sigaction(SIGINT, NULL, &osa);
+       if (osa.sa_handler != SIG_IGN)
+       {
+               sigemptyset(&sa.sa_mask);
+               sa.sa_flags = 0;
+               sa.sa_handler = sighandler;
+               sigaction(SIGINT, &sa, &osa);
+        }
+
+       // Set the new terminal attributes
+       if (tcsetattr(STDIN_FILENO, 0, &new_attr) < 0)
+               return -1;
+#endif
+
+       size_t nread = 0;
+       int ch = 0;
+       while ((ch = getchar()) != '\n' && ch != EOF)
+       {
+               // Check buffer size
+               if ((nread+2) > size)
+                       continue;
+
+               putchar('*');
+               buffer[nread] = ch;
+               nread++;
+       }
+
+       putchar('\n');
+       buffer[nread] = '\0';
+
+#ifdef _WIN32
+       // Restore the console mode
+       if (!SetConsoleMode(hstdin, mode))
+               return -1;
+#else
+       // Restore terminal
+       if (tcsetattr(STDIN_FILENO, 0, &old_attr) < 0)
+               return -1;
+
+       // Restore the signal
+       sigaction(SIGINT, &osa, NULL);
+       if (signo)
+               raise(signo);
+#endif
+
+       return nread;
+}
+
+// Get a password from the user
+int getPW(char* pin, char* newPIN, CK_ULONG userType)
+{
+       char password1[MAX_PIN_LEN+1];
+       char password2[MAX_PIN_LEN+1];
+       size_t size = MAX_PIN_LEN+1;
+       int length = 0;
+
+       // Check if the user has provided a password
+       if (pin)
+       {
+               length = strlen(pin);
+               // Save the PIN if it has the correct length
+               if (length >= MIN_PIN_LEN && length <= MAX_PIN_LEN)
+                       memcpy(password1, pin, length+1);
+       }
+
+       while (length < MIN_PIN_LEN || length > MAX_PIN_LEN)
+       {
+               if (userType == CKU_SO)
+               {
+                       printf("=== SO PIN (%i-%i characters) ===\n",
+                               MIN_PIN_LEN, MAX_PIN_LEN);
+                       length = getpin("Please enter SO PIN: ",
+                                       password1, size);
+               }
+               else
+               {
+                       printf("=== User PIN (%i-%i characters) ===\n",
+                               MIN_PIN_LEN, MAX_PIN_LEN);
+                       length = getpin("Please enter user PIN: ",
+                                       password1, size);
+               }
+
+               if (length < 0)
+                       return 1;
+               if (length < MIN_PIN_LEN || length > MAX_PIN_LEN)
+               {
+                       fprintf(stderr, "ERROR: The length of the PIN is out of range.\n");
+                       length = 0;
+                       continue;
+               }
+
+               if (userType == CKU_SO)
+               {
+                       length = getpin("Please reenter SO PIN: ",
+                                       password2, size);
+               }
+               else
+               {
+                       length = getpin("Please reenter user PIN: ",
+                                       password2, size);
+               }
+
+               if (length < 0)
+                       return 1;
+               if (strcmp(password1, password2))
+               {
+                       fprintf(stderr, "ERROR: The entered PINs are not equal.\n");
+                       length = 0;
+                       continue;
+               }
+       }
+
+       memcpy(newPIN, password1, length+1);
+       return 0;
+}
diff --git a/SoftHSMv2/src/bin/common/getpw.h b/SoftHSMv2/src/bin/common/getpw.h
new file mode 100644 (file)
index 0000000..1ca15a5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ getpw.h
+
+ Helper function to get a password from the user
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BIN_GETPW_H
+#define _SOFTHSM_V2_BIN_GETPW_H
+
+#include "cryptoki.h"
+
+int getPW(char* pin, char* newPIN, CK_ULONG userType);
+
+#endif // !_SOFTHSM_V2_BIN_GETPW_H
diff --git a/SoftHSMv2/src/bin/common/library.cpp b/SoftHSMv2/src/bin/common/library.cpp
new file mode 100644 (file)
index 0000000..af0dd93
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ library.cpp
+
+ Support function for handling PKCS#11 libraries
+ *****************************************************************************/
+
+#include <config.h>
+#include "library.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(HAVE_DLOPEN)
+#include <dlfcn.h>
+#endif
+
+// Load the PKCS#11 library
+CK_C_GetFunctionList loadLibrary(char* module, void** moduleHandle,
+                               char **pErrMsg)
+{
+       CK_C_GetFunctionList pGetFunctionList = NULL;
+
+#if defined(HAVE_LOADLIBRARY)
+       HINSTANCE hDLL = NULL;
+       DWORD dw = NULL;
+       static char errMsg[100];
+
+       // Load PKCS #11 library
+       if (module)
+       {
+               hDLL = LoadLibraryA(module);
+       }
+       else
+       {
+               hDLL = LoadLibraryA(DEFAULT_PKCS11_LIB);
+       }
+
+       if (hDLL == NULL)
+       {
+               // Failed to load the PKCS #11 library
+               dw = GetLastError();
+               snprintf((char*)errMsg, sizeof(errMsg), "LoadLibraryA failed: 0x%08X", dw);
+               *pErrMsg = errMsg;
+               return NULL;
+       }
+       else
+       {
+               *pErrMsg = NULL;
+       }
+
+       // Retrieve the entry point for C_GetFunctionList
+       pGetFunctionList = (CK_C_GetFunctionList) GetProcAddress(hDLL, "C_GetFunctionList");
+       if (pGetFunctionList == NULL)
+       {
+               dw = GetLastError();
+               snprintf((char*)errMsg, sizeof(errMsg), "getProcAddress failed: 0x%08X", dw);
+               *pErrMsg = errMsg;
+               FreeLibrary(hDLL);
+               return NULL;
+       }
+
+       // Store the handle so we can FreeLibrary it later
+       *moduleHandle = hDLL;
+
+#elif defined(HAVE_DLOPEN)
+       void* pDynLib = NULL;
+
+       // Load PKCS #11 library
+       if (module)
+       {
+               pDynLib = dlopen(module, RTLD_NOW | RTLD_LOCAL);
+       }
+       else
+       {
+               pDynLib = dlopen(DEFAULT_PKCS11_LIB, RTLD_NOW | RTLD_LOCAL);
+       }
+
+       *pErrMsg = dlerror();
+       if (pDynLib == NULL || *pErrMsg != NULL)
+       {
+               if (pDynLib != NULL) dlclose(pDynLib);
+
+               // Failed to load the PKCS #11 library
+               return NULL;
+       }
+
+       // Retrieve the entry point for C_GetFunctionList
+       pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList");
+
+       // Store the handle so we can dlclose it later
+       *pErrMsg = dlerror();
+       if (*pErrMsg != NULL)
+       {
+               dlclose(pDynLib);
+
+               // An error occured during dlsym()
+               return NULL;
+       }
+
+       *moduleHandle = pDynLib;
+#else
+       fprintf(stderr, "ERROR: Not compiled with library support.\n");
+
+       return NULL;
+#endif
+
+       return pGetFunctionList;
+}
+
+void unloadLibrary(void* moduleHandle)
+{
+       if (moduleHandle)
+       {
+#if defined(HAVE_LOADLIBRARY)
+               FreeLibrary((HMODULE) moduleHandle);
+#elif defined(HAVE_DLOPEN)
+               dlclose(moduleHandle);
+#endif
+       }
+}
diff --git a/SoftHSMv2/src/bin/common/library.h b/SoftHSMv2/src/bin/common/library.h
new file mode 100644 (file)
index 0000000..6c6b3e4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ library.h
+
+ Support function for handling PKCS#11 libraries
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BIN_LIBRARY_H
+#define _SOFTHSM_V2_BIN_LIBRARY_H
+
+#include "cryptoki.h"
+
+CK_C_GetFunctionList loadLibrary(char* module, void** moduleHandle,
+                               char **pErrMsg);
+void unloadLibrary(void* moduleHandle);
+
+#endif // !_SOFTHSM_V2_BIN_LIBRARY_H
diff --git a/SoftHSMv2/src/bin/dump/Makefile.am b/SoftHSMv2/src/bin/dump/Makefile.am
new file mode 100644 (file)
index 0000000..c70d6f6
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =          -I$(srcdir)/../../lib \
+                       -I$(srcdir)/../../lib/object_store \
+                       -I$(srcdir)/../../lib/pkcs11 \
+                       @SQLITE3_INCLUDES@
+
+dist_man_MANS =                softhsm2-dump-file.1
+
+bin_PROGRAMS =         softhsm2-dump-file
+
+if BUILD_OBJECTSTORE_BACKEND_DB
+dist_man_MANS +=       softhsm2-dump-db.1
+bin_PROGRAMS +=                softhsm2-dump-db
+endif
+
+softhsm2_dump_file_SOURCES =   softhsm2-dump-file.cpp
+
+softhsm2_dump_db_SOURCES = softhsm2-dump-db.cpp
+
+softhsm2_dump_db_LDADD = @SQLITE3_LIBS@ @YIELD_LIB@
+
+EXTRA_DIST =           $(srcdir)/*.h \
+                       softhsm2-dump-db.1
diff --git a/SoftHSMv2/src/bin/dump/common.h b/SoftHSMv2/src/bin/dump/common.h
new file mode 100644 (file)
index 0000000..d38b924
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ common.h
+
+ Common definitions for SoftHSMv2 dump.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_COMMON_H
+#define _SOFTHSM_V2_COMMON_H
+
+#include <config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+#include <set>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include "tables.h"
+
+// Table of attribute types
+std::map<unsigned long, std::string> CKA_table;
+
+// Dump an attribute type
+void dumpCKA(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKA_table.empty())
+       {
+               fill_CKA_table(CKA_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKA_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKA_VENDOR_DEFINED)
+               {
+                       cka &= ~CKA_VENDOR_DEFINED;
+                       printf("CKA_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Table of mechanism types
+std::map<unsigned long, std::string> CKM_table;
+
+// Dump a mechanism type
+void dumpCKM(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKM_table.empty())
+       {
+               fill_CKM_table(CKM_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKM_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKM_VENDOR_DEFINED)
+               {
+                       cka &= ~CKM_VENDOR_DEFINED;
+                       printf("CKM_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Table of object classes
+std::map<unsigned long, std::string> CKO_table;
+
+// Dump a object class
+void dumpCKO(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKO_table.empty())
+       {
+               fill_CKO_table(CKO_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKO_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKO_VENDOR_DEFINED)
+               {
+                       cka &= ~CKO_VENDOR_DEFINED;
+                       printf("CKO_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Table of hw feature types
+std::map<unsigned long, std::string> CKH_table;
+
+// Dump a hw feature type
+void dumpCKH(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKH_table.empty())
+       {
+               fill_CKH_table(CKH_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKH_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKH_VENDOR_DEFINED)
+               {
+                       cka &= ~CKH_VENDOR_DEFINED;
+                       printf("CKH_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Table of key types
+std::map<unsigned long, std::string> CKK_table;
+
+// Dump a key type
+void dumpCKK(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKK_table.empty())
+       {
+               fill_CKK_table(CKK_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKK_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKK_VENDOR_DEFINED)
+               {
+                       cka &= ~CKK_VENDOR_DEFINED;
+                       printf("CKK_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Table of certificate types
+std::map<unsigned long, std::string> CKC_table;
+
+// Dump a certificate type
+void dumpCKC(unsigned long cka, int size)
+{
+       // Lazy fill
+       if (CKC_table.empty())
+       {
+               fill_CKC_table(CKC_table);
+       }
+       std::string msg;
+       try
+       {
+               msg = CKC_table.at(cka);
+               printf("%.*s", size, msg.c_str());
+       }
+       catch (const std::out_of_range&)
+       {
+               if (cka & CKC_VENDOR_DEFINED)
+               {
+                       cka &= ~CKC_VENDOR_DEFINED;
+                       printf("CKC_VENDOR_DEFINED | 0x%lx", cka);
+               }
+               else
+               {
+                       printf("unknown 0x%lx", cka);
+               }
+       }
+}
+
+// Dump a PKCS#11 integer type
+void dumpCKx(uint64_t cka, uint64_t value, int size)
+{
+       if ((uint32_t)value == (uint32_t)~0)
+       {
+               printf("CK_UNAVAILABLE_INFORMATION");
+               return;
+       }
+
+       switch ((unsigned long) cka)
+       {
+       case CKA_CLASS:
+               if ((uint64_t)((uint32_t)value) != value)
+               {
+                       printf("overflow object class");
+                       break;
+               }
+               dumpCKO((unsigned long) value, size);
+               break;
+       case CKA_CERTIFICATE_TYPE:
+               if ((uint64_t)((uint32_t)value) != value)
+               {
+                       printf("overflow certificate type");
+                       break;
+               }
+               dumpCKC((unsigned long) value, size);
+               break;
+       case CKA_KEY_TYPE:
+               if ((uint64_t)((uint32_t)value) != value)
+               {
+                       printf("overflow key type");
+                       break;
+               }
+               dumpCKK((unsigned long) value, size);
+               break;
+       case CKA_KEY_GEN_MECHANISM:
+               if ((uint64_t)((uint32_t)value) != value)
+               {
+                       printf("overflow mechanism type");
+                       break;
+               }
+               dumpCKM((unsigned long) value, size);
+               break;
+       case CKA_HW_FEATURE_TYPE:
+               if ((uint64_t)((uint32_t)value) != value)
+               {
+                       printf("overflow hw feature type");
+                       break;
+               }
+               dumpCKH((unsigned long) value, size);
+               break;
+       default:
+               printf("CK_ULONG %lu(0x%lx)",
+                      (unsigned long) value,
+                      (unsigned long) value);
+               break;
+       }
+}
+
+// Dump a boolean (in fact unsigned 8 bit long) value, true is 0xff
+void dumpBool(uint8_t value, bool inArray = false)
+{
+       printf("%02hhx                      %s", value, inArray ? " " : "");
+       switch (value)
+       {
+       case 0:
+               printf("FALSE");
+               break;
+       case 0xff:
+               printf("TRUE");
+               break;
+       default:
+               printf("(invalid) TRUE");
+               break;
+       }
+}
+
+// Dump a boolean (in fact unsigned 8 bit long) value, true is 1
+void dumpBool1(uint8_t value, bool inArray = false)
+{
+       printf("%02hhx                      %s", value, inArray ? " " : "");
+       switch (value)
+       {
+       case 0:
+               printf("FALSE");
+               break;
+       case 1:
+               printf("TRUE");
+               break;
+       default:
+               printf("(invalid) TRUE");
+               break;
+       }
+}
+
+// Dump an unsigned 64 bit long value
+void dumpULong(uint64_t value, bool inArray = false)
+{
+       for (int i = 56; i >= 0; i -= 8)
+       {
+               uint8_t v;
+               v = (value >> i) & 0xff;
+               printf("%02hhx ", v);
+       }
+       if (inArray)
+       {
+               printf(" ");
+       }
+}
+
+// Dump an unsigned 32 bit long value
+void dumpU32(uint32_t value, bool inArray = false)
+{
+       for (int i = 24; i >= 0; i -= 8)
+       {
+               uint8_t v;
+               v = (value >> i) & 0xff;
+               printf("%02hhx ", v);
+       }
+       printf("            ");
+       if (inArray)
+       {
+               printf(" ");
+       }
+}
+
+// Dump a byte string (aka uint8_t vector) value
+void dumpBytes(const std::vector<uint8_t>& value, bool inArray = false)
+{
+       size_t len = value.size();
+       size_t i = 0;
+       while (i + 8 <= len)
+       {
+               for (size_t j = 0; j < 8; j++)
+               {
+                       printf("%02hhx ", value[i + j]);
+               }
+               if (inArray)
+               {
+                       printf(" ");
+               }
+               printf("<");
+               for (size_t j = 0; j < 8; j++)
+               {
+                       uint8_t c = value[i + j];
+                       if (isgraph((int) c) == 0)
+                       {
+                               printf(".");
+                       }
+                       else
+                       {
+                               printf("%c", (int) c);
+                       }
+               }
+               printf(">\n");
+               i += 8;
+       }
+       len -= i;
+       if (len == 0)
+       {
+               return;
+       }
+
+       for (size_t j = 0; j < len; j++)
+       {
+               printf("%02hhx ", value[i + j]);
+       }
+       for (size_t j = len; j < 8; j++)
+       {
+               printf("   ");
+       }
+       if (inArray)
+       {
+               printf(" ");
+       }
+       printf("<");
+       for (size_t j = 0; j < len; j++)
+       {
+               uint8_t c = value[i + j];
+               if (isgraph((int) c) == 0)
+               {
+                       printf(".");
+               }
+               else
+               {
+                       printf("%c", (int) c);
+               }
+       }
+       for (size_t j =len; j < 8; j++)
+       {
+               printf(" ");
+       }
+       printf(">\n");
+}
+
+// Attribute (in an array) template
+template<typename T, typename K, typename I>
+class AttributeTK
+{
+public:
+       T type;
+       K kind;
+
+       uint8_t boolValue;
+       I ulongValue;
+       std::vector<uint8_t> bytestrValue;
+       std::set<I> mechSetValue;
+
+       // Dump an array (in fact an Attribute vector) value
+       void dumpType() const;
+       void dumpKind() const;
+       void dumpBoolValue() const;
+       void dumpULongValue(I value) const;
+       bool isBoolean() const;
+       bool isInteger() const;
+       bool isBinary() const;
+       bool isMechSet() const;
+       void dump() const {
+               dumpType();
+               if ((sizeof(type) > 4) &&
+                   ((uint64_t)((uint32_t)type) != type))
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) type, 47);
+                       printf("\n");
+               }
+
+               dumpKind();
+               if (isBoolean())
+               {
+                       printf("boolean attribute\n");
+                       dumpBoolValue();
+                       printf("\n");
+               }
+               else if (isInteger())
+               {
+                       printf("unsigned long attribute\n");
+                       dumpULongValue(ulongValue);
+                       dumpCKx(type, ulongValue, 47);
+                       printf("\n");
+               }
+               else if (isBinary())
+               {
+                       printf("byte string attribute\n");
+                       I size = bytestrValue.size();
+                       dumpULongValue(size);
+                       printf("(length %lu)\n", (unsigned long) size);
+                       dumpBytes(bytestrValue, true);
+               }
+               else if (isMechSet())
+               {
+                       printf("mechanism set attribute\n");
+                       I size = mechSetValue.size();
+                       dumpULongValue(size);
+                       printf("(length %lu)\n", (unsigned long) size);
+                       for (typename std::set<I>::const_iterator i = mechSetValue.begin(); i != mechSetValue.end(); ++i)
+                       {
+                                dumpULongValue(*i);
+                                dumpCKM(*i, 47);
+                                printf("\n");
+                        }
+               }
+               else
+               {
+                       printf("unknown attribute format\n");
+               }
+       }
+};
+
+#endif // !_SOFTHSM_V2_COMMON_H
diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-db.1 b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.1
new file mode 100644 (file)
index 0000000..00f455b
--- /dev/null
@@ -0,0 +1,18 @@
+.TH SOFTHSM2-DUMP-DB 1 "20 March 2014" "SoftHSM"
+.SH NAME
+softhsm2-dump-db \- SoftHSM database dump
+.SH SYNOPSIS
+.PP
+.B softhsm2-dump-db
+.I path
+.SH DESCRIPTION
+.B softhsm2-dump
+is a tool that can dump SoftHSM v2 database for debugging purposes.
+.LP
+.SH OPTIONS
+.TP
+.B \fIpath\fR
+The SoftHSM v2 database file that is going to be dumped.
+.TP
+.B \-\-help\fR, \fB\-h\fR
+Show the help information.
diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp
new file mode 100644 (file)
index 0000000..f55a9db
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-dump-db.cpp
+
+ This program can be used for dumping SoftHSM v2 database.
+ *****************************************************************************/
+
+#include <config.h>
+
+#include <sched.h>
+#include <sqlite3.h>
+#include <string.h>
+
+#include "common.h"
+
+// Attribute types in database arrays
+enum AttributeKind
+{
+       akUnknown,
+       akBoolean,
+       akInteger,
+       akBinary,
+       akArray
+};
+
+// Attribute specialization
+typedef AttributeTK<CK_ATTRIBUTE_TYPE, AttributeKind, unsigned long> Attribute;
+
+template<>
+bool Attribute::isBoolean() const
+{
+       return kind == akBoolean;
+}
+
+template<>
+bool Attribute::isInteger() const
+{
+       return kind == akInteger;
+}
+
+template<>
+bool Attribute::isBinary() const
+{
+       return kind == akBinary;
+}
+
+template<>
+bool Attribute::isMechSet() const
+{
+       // Mechanism sets are stored as binary in the database
+       return false;
+}
+
+template<>
+void Attribute::dumpType() const
+{
+       if (sizeof(type) == 4)
+       {
+               dumpU32((uint32_t)type, true);
+       }
+       else
+       {
+               dumpULong(type, true);
+       }
+}
+
+template<>
+void Attribute::dumpKind() const
+{
+       dumpU32((uint32_t) kind, true);
+}
+
+template<>
+void Attribute::dumpBoolValue() const
+{
+       dumpBool1(boolValue, true);
+}
+
+template<>
+void Attribute::dumpULongValue(unsigned long value) const
+{
+       if (sizeof(unsigned long) == 4)
+       {
+               dumpU32(value, true);
+       }
+       else
+       {
+               dumpULong(value, true);
+       }
+}
+
+// dumpArray specialization
+typedef std::vector<Attribute> va_type;
+
+void dumpArray(const va_type& value)
+{
+       for (va_type::const_iterator attr = value.begin(); attr != value.end(); ++attr)
+               attr->dump();
+}
+
+// Get a boolean (in fact unsigned 8 bit long) value
+bool getBool(sqlite3* db, long long oid, long long id, uint64_t& type, uint8_t& value)
+{
+       int rv;
+       sqlite3_stmt* sql = NULL;
+       std::string command = "select type,value from attribute_boolean where object_id=? and id=?;";
+
+       value = 0;
+
+       rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr,
+                       "can't find boolean attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       rv = sqlite3_bind_int64(sql, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       sqlite3_bind_int64(sql, 2, id);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the attribute id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       while ((rv = sqlite3_step(sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr,
+                       "can't read boolean attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       type = sqlite3_column_int64(sql, 0);
+       value = sqlite3_column_int(sql, 1);
+       sqlite3_finalize(sql);
+
+       return true;
+}
+
+// Get an unsigned 64 bit long value
+bool getULong(sqlite3* db, long long oid, long long id, uint64_t& type, uint64_t& value)
+{
+       int rv;
+       sqlite3_stmt* sql = NULL;
+       std::string command = "select type,value from attribute_integer where object_id=? and id=?;";
+
+       value = 0ULL;
+
+       rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr,
+                       "can't find integer attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       rv = sqlite3_bind_int64(sql, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       sqlite3_bind_int64(sql, 2, id);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the attribute id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       while ((rv = sqlite3_step(sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr,
+                       "can't read integer attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       type = sqlite3_column_int64(sql, 0);
+       value = sqlite3_column_int64(sql, 1);
+       sqlite3_finalize(sql);
+
+       return true;
+}
+
+// Get a byte string (aka uint8_t vector) value
+bool getBytes(sqlite3* db, long long oid, long long id, uint64_t& type, std::vector<uint8_t>& value)
+{
+       int rv;
+       sqlite3_stmt* sql = NULL;
+       std::string command = "select type,value from attribute_binary where object_id=? and id=?;";
+       size_t len;
+       const uint8_t* val;
+
+       value.clear();
+
+       rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr,
+                       "can't find binary attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       rv = sqlite3_bind_int64(sql, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       sqlite3_bind_int64(sql, 2, id);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the attribute id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       while ((rv = sqlite3_step(sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr,
+                       "can't read binary attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       type = sqlite3_column_int64(sql, 0);
+       len = sqlite3_column_bytes(sql, 1);
+       val = (const uint8_t*) sqlite3_column_blob(sql, 1);
+       for (size_t i = 0; i < len; ++i)
+       {
+               value.push_back(val[i]);
+       }
+       sqlite3_finalize(sql);
+
+       return true;
+}
+
+// Get an array (aka Attribute vector) value
+bool getArray(sqlite3* db, long long oid, long long id, uint64_t& type, std::vector<Attribute>& value)
+{
+       int rv;
+       sqlite3_stmt* sql = NULL;
+       std::string command = "select type,value from attribute_array where object_id=? and id=?;";
+       size_t len;
+       const uint8_t* val;
+
+       value.clear();
+
+       rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr,
+                       "can't find array attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       rv = sqlite3_bind_int64(sql, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       sqlite3_bind_int64(sql, 2, id);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the attribute id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       while ((rv = sqlite3_step(sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr,
+                       "can't read array attribute id=%lld object=%lld: %d(%s)\n",
+                       id, oid, rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sql);
+               return false;
+       }
+       type = sqlite3_column_int64(sql, 0);
+       len = sqlite3_column_bytes(sql, 1);
+       val = (const uint8_t*) sqlite3_column_blob(sql, 1);
+
+// CK_ATTRIBUTE_TYPE type, AttributeKind kind
+//  bool -> int, integer -> unsigned long, binary -> unsigned long + vector
+
+       for (size_t pos = 0; pos < len; )
+       {
+               // finished?
+               if (pos == len) break;
+
+               Attribute attr;
+
+               if (pos + sizeof(attr.type) > len)
+               {
+                       fprintf(stderr, "overflow array item type\n");
+                       sqlite3_finalize(sql);
+                       return false;
+               }
+               memcpy(&attr.type, val + pos, sizeof(attr.type));
+               pos += sizeof(attr.type);
+
+               if (pos + sizeof(attr.kind) > len)
+               {
+                       fprintf(stderr, "overflow array item kind\n");
+                       sqlite3_finalize(sql);
+                       return false;
+               }
+               memcpy(&attr.kind, val + pos, sizeof(attr.kind));
+               pos += sizeof(attr.kind);
+
+               if (attr.kind == akBoolean)
+               {
+                       if (pos + sizeof(attr.boolValue) > len)
+                       {
+                               fprintf(stderr, "overflow array boolean item\n");
+                               sqlite3_finalize(sql);
+                               return false;
+                       }
+                       memcpy(&attr.boolValue, val + pos, sizeof(attr.boolValue));
+                       pos += sizeof(attr.boolValue);
+               }
+               else if (attr.kind == akInteger)
+               {
+                       if (pos + sizeof(attr.ulongValue) > len)
+                       {
+                               fprintf(stderr, "overflow array integer item\n");
+                               sqlite3_finalize(sql);
+                               return false;
+                       }
+                       memcpy(&attr.ulongValue, val + pos, sizeof(attr.ulongValue));
+                       pos += sizeof(attr.ulongValue);
+               }
+               else if (attr.kind == akBinary)
+               {
+                       unsigned long size;
+                       if (pos + sizeof(size) > len)
+                       {
+                               fprintf(stderr, "overflow array binary item\n");
+                               sqlite3_finalize(sql);
+                               return false;
+                       }
+                       memcpy(&size, val + pos, sizeof(size));
+                       pos += sizeof(size);
+
+                       if (pos + size > len)
+                       {
+                               fprintf(stderr, "overflow array binary item\n");
+                               sqlite3_finalize(sql);
+                               return false;
+                       }
+                       attr.bytestrValue.resize(size);
+                       for (unsigned long i = 0; i < size; ++i)
+                       {
+                               attr.bytestrValue[i] = val[pos + i];
+                       }
+                       pos += size;
+               }
+               else
+               {
+                       fprintf(stderr, "unknown array item\n");
+                       sqlite3_finalize(sql);
+                       return false;
+               }
+
+               value.push_back(attr);
+       }
+       sqlite3_finalize(sql);
+
+       return true;
+}
+
+// Dump boolean attributes of an object
+void dump_booleans(sqlite3* db, long long oid)
+{
+       int rv;
+       unsigned long count;
+       sqlite3_stmt* sqlcnt = NULL;
+       sqlite3_stmt* sqlid = NULL;
+       std::string commandcnt = "select count(id) from attribute_boolean where object_id=?;";
+       std::string commandid = "select id from attribute_boolean where object_id=?;";
+       rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlcnt, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       count = sqlite3_column_int(sqlcnt, 0);
+       sqlite3_finalize(sqlcnt);
+       if (count == 0)
+               return;
+
+       printf("%lu boolean attributes for object %lld\n", count, oid);
+
+       rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlid, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       while (count-- > 0) {
+               while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
+               {
+                       sched_yield();
+               }
+               if (rv != SQLITE_ROW)
+               {
+                       if (rv != SQLITE_DONE)
+                       {
+                               fprintf(stderr,
+                                       "can't get next object id: %d(%s)\n",
+                                       rv, sqlite3_errmsg(db));
+                       }
+                       sqlite3_finalize(sqlid);
+                       return;
+               }
+               long long id = sqlite3_column_int64(sqlid, 0);
+
+               uint64_t type;
+               uint8_t value;
+               if (!getBool(db, oid, id, type, value))
+               {
+                       return;
+               }
+               dumpULong(type);
+               if ((uint64_t)((uint32_t)type) != type)
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) type, 48);
+                       printf("\n");
+               }
+
+               dumpBool1(value);
+               printf("\n");
+       }
+}
+
+// Dump integer attributes of an object
+void dump_integers(sqlite3* db, long long oid)
+{
+       int rv;
+       unsigned long count;
+       sqlite3_stmt* sqlcnt = NULL;
+       sqlite3_stmt* sqlid = NULL;
+       std::string commandcnt = "select count(id) from attribute_integer where object_id=?;";
+       std::string commandid = "select id from attribute_integer where object_id=?;";
+       rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlcnt, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       count = sqlite3_column_int(sqlcnt, 0);
+       sqlite3_finalize(sqlcnt);
+       if (count == 0)
+               return;
+
+       printf("%lu integer attributes for object %lld\n", count, oid);
+
+       rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlid, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       while (count-- > 0) {
+               while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
+               {
+                       sched_yield();
+               }
+               if (rv != SQLITE_ROW)
+               {
+                       if (rv != SQLITE_DONE)
+                       {
+                               fprintf(stderr,
+                                       "can't get next object id: %d(%s)\n",
+                                       rv, sqlite3_errmsg(db));
+                       }
+                       sqlite3_finalize(sqlid);
+                       return;
+               }
+               long long id = sqlite3_column_int64(sqlid, 0);
+
+               uint64_t type;
+               uint64_t value;
+               if (!getULong(db, oid, id, type, value))
+               {
+                       return;
+               }
+               dumpULong(type);
+               if ((uint64_t)((uint32_t)type) != type)
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) type, 48);
+                       printf("\n");
+               }
+               dumpULong(value);
+               dumpCKx(type, value, 48);
+               printf("\n");
+       }
+}
+
+// Dump binary attributes of an object
+void dump_binaries(sqlite3* db, long long oid)
+{
+       int rv;
+       unsigned long count;
+       sqlite3_stmt* sqlcnt = NULL;
+       sqlite3_stmt* sqlid = NULL;
+       std::string commandcnt = "select count(id) from attribute_binary where object_id=?;";
+       std::string commandid = "select id from attribute_binary where object_id=?;";
+       rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlcnt, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       count = sqlite3_column_int(sqlcnt, 0);
+       sqlite3_finalize(sqlcnt);
+       if (count == 0)
+               return;
+
+       printf("%lu binary attributes for object %lld\n", count, oid);
+
+       rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlid, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       while (count-- > 0) {
+               while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
+               {
+                       sched_yield();
+               }
+               if (rv != SQLITE_ROW)
+               {
+                       if (rv != SQLITE_DONE)
+                       {
+                               fprintf(stderr,
+                                       "can't get next object id: %d(%s)\n",
+                                       rv, sqlite3_errmsg(db));
+                       }
+                       sqlite3_finalize(sqlid);
+                       return;
+               }
+               long long id = sqlite3_column_int64(sqlid, 0);
+
+               uint64_t type;
+               std::vector<uint8_t> value;
+               if (!getBytes(db, oid, id, type, value))
+               {
+                       return;
+               }
+               dumpULong(type);
+               if ((uint64_t)((uint32_t)type) != type)
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) type, 48);
+                       printf("\n");
+               }
+               dumpULong((uint64_t) value.size());
+               printf("(length %lu)\n", (unsigned long) value.size());
+               dumpBytes(value);
+       }
+}
+
+// Dump array attributes of an object
+void dump_arrays(sqlite3* db, long long oid)
+{
+       int rv;
+       unsigned long count;
+       sqlite3_stmt* sqlcnt = NULL;
+       sqlite3_stmt* sqlid = NULL;
+       std::string commandcnt = "select count(id) from attribute_array where object_id=?;";
+       std::string commandid = "select id from attribute_array where object_id=?;";
+       rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlcnt, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       count = sqlite3_column_int(sqlcnt, 0);
+       sqlite3_finalize(sqlcnt);
+       if (count == 0)
+               return;
+
+       printf("%lu array attributes for object %lld\n", count, oid);
+
+       rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       rv = sqlite3_bind_int64(sqlid, 1, oid);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't bind the object id: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       while (count-- > 0) {
+               while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
+               {
+                       sched_yield();
+               }
+               if (rv != SQLITE_ROW)
+               {
+                       if (rv != SQLITE_DONE)
+                       {
+                               fprintf(stderr,
+                                       "can't get next object id: %d(%s)\n",
+                                       rv, sqlite3_errmsg(db));
+                       }
+                       sqlite3_finalize(sqlid);
+                       return;
+               }
+               long long id = sqlite3_column_int64(sqlid, 0);
+
+               uint64_t type;
+               std::vector<Attribute> value;
+               if (!getArray(db, oid, id, type, value))
+               {
+                       return;
+               }
+               dumpULong(type);
+               if ((uint64_t)((uint32_t)type) != type)
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) type, 48);
+                       printf("\n");
+               }
+               dumpULong((uint64_t) value.size());
+               printf("(length %lu)\n", (unsigned long) value.size());
+               dumpArray(value);
+       }
+}
+
+// Dump an object
+void dump_object(sqlite3* db, long long oid)
+{
+       printf("dump object id=%lld\n", oid);
+       dump_booleans(db, oid);
+       dump_integers(db, oid);
+       dump_binaries(db, oid);
+       dump_arrays(db, oid);
+}
+
+// Core function
+void dump(sqlite3* db)
+{
+       int rv;
+       unsigned long count;
+       sqlite3_stmt* sqlcnt = NULL;
+       sqlite3_stmt* sqlid = NULL;
+       std::string commandcnt = "select count(id) from object;";
+       std::string commandid =  "select id from object;";
+
+       rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+       if (rv != SQLITE_ROW)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlcnt);
+               return;
+       }
+       count = sqlite3_column_int(sqlcnt, 0);
+       sqlite3_finalize(sqlcnt);
+       printf("%lu objects\n", count);
+
+       rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't count the object table: %d(%s)\n",
+                       rv, sqlite3_errmsg(db));
+               sqlite3_finalize(sqlid);
+               return;
+       }
+       while (count-- > 0) {
+               while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
+               {
+                       sched_yield();
+               }
+               if (rv != SQLITE_ROW)
+               {
+                       if (rv != SQLITE_DONE)
+                       {
+                               fprintf(stderr,
+                                       "can't get next object id: %d(%s)\n",
+                                       rv, sqlite3_errmsg(db));
+                       }
+                       sqlite3_finalize(sqlid);
+                       return;
+               }
+               long long oid = sqlite3_column_int64(sqlid, 0);
+               dump_object(db, oid);
+       }
+}
+
+// Display the usage
+void usage()
+{
+       printf("SoftHSM dump tool. From SoftHSM v2 database.\n");
+       printf("Usage: softhsm2-dump-db path\n");
+}
+
+// Check the existence of a table
+void check_table_exist(sqlite3* db, std::string name)
+{
+       int rv;
+       std::string command = "select count(id) from " + name + ";";
+
+       rv = sqlite3_exec(db, command.c_str(), NULL, NULL, NULL);
+       if (rv != SQLITE_OK)
+       {
+               fprintf(stderr, "can't find '%s' table\n", name.c_str());
+               sqlite3_close(db);
+               exit(0);
+       }
+}
+
+// The main function
+int main(int argc, char* argv[])
+{
+       int rv;
+       sqlite3* db = NULL;
+
+       if (argc != 2)
+       {
+               usage();
+               exit(0);
+       }
+
+       rv = sqlite3_open_v2(argv[1], &db, SQLITE_OPEN_READONLY, NULL);
+       if (rv != SQLITE_OK)
+       {
+               if (db == NULL)
+               {
+                       fprintf(stderr,
+                               "can't open database file %s\n",
+                               argv[1]);
+               }
+               else
+               {
+                       fprintf(stderr,
+                               "can't open database file %s: %d(%s)\n",
+                               argv[1],
+                               rv,
+                               sqlite3_errmsg(db));
+               }
+               sqlite3_close(db);
+               exit(0);
+       }
+
+       // No user version to check
+
+       check_table_exist(db, "object");
+       check_table_exist(db, "attribute_boolean");
+       check_table_exist(db, "attribute_integer");
+       check_table_exist(db, "attribute_binary");
+       check_table_exist(db, "attribute_array");
+
+       printf("Dump of object file \"%s\"\n", argv[1]);
+       dump(db);
+       sqlite3_close(db);
+       exit(1);
+}
diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-file.1 b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.1
new file mode 100644 (file)
index 0000000..5167f70
--- /dev/null
@@ -0,0 +1,18 @@
+.TH SOFTHSM2-DUMP-FILE 1 "20 March 2014" "SoftHSM"
+.SH NAME
+softhsm2-dump-file \- SoftHSM object file dump
+.SH SYNOPSIS
+.PP
+.B softhsm2-dump-file
+.I path
+.SH DESCRIPTION
+.B softhsm2-dump-file
+is a tool that can dump SoftHSM v2 object file for debugging purposes.
+.LP
+.SH OPTIONS
+.TP
+.B \fIpath\fR
+The SoftHSM v2 object file that is going to be dumped.
+.TP
+.B \-\-help\fR, \fB\-h\fR
+Show the help information.
diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp
new file mode 100644 (file)
index 0000000..994f67e
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-dump-file.cpp
+
+ This program can be used for dumping SoftHSM v2 object files.
+ *****************************************************************************/
+
+#include <config.h>
+
+#include "common.h"
+
+// Attribute types on disk
+#define BOOLEAN_ATTR           0x1
+#define ULONG_ATTR             0x2
+#define BYTES_ATTR             0x3
+#define ATTRMAP_ATTR           0x4
+#define MECHSET_ATTR           0x5
+
+// Maximum byte string length (1Gib)
+#define MAX_BYTES              0x3fffffff
+
+typedef AttributeTK<uint64_t, uint64_t, uint64_t> Attribute;
+
+// Attribute specialization
+template<>
+bool Attribute::isBoolean() const
+{
+       return kind == BOOLEAN_ATTR;
+}
+
+template<>
+bool Attribute::isInteger() const
+{
+       return kind == ULONG_ATTR;
+}
+
+template<>
+bool Attribute::isBinary() const
+{
+       return kind == BYTES_ATTR;
+}
+
+template<>
+bool Attribute::isMechSet() const
+{
+       return kind == MECHSET_ATTR;
+}
+
+template<>
+void Attribute::dumpType() const
+{
+       dumpULong(type, true);
+}
+
+template<>
+void Attribute::dumpKind() const
+{
+       dumpULong(kind, true);
+}
+
+template<>
+void Attribute::dumpBoolValue() const
+{
+       dumpBool(boolValue, true);
+}
+
+template<>
+void Attribute::dumpULongValue(uint64_t value) const
+{
+       dumpULong(value, true);
+}
+
+// dumpMap specialization
+typedef std::vector<Attribute> va_type;
+
+void dumpMap(const va_type& value)
+{
+       for (va_type::const_iterator attr = value.begin(); attr != value.end(); ++attr)
+               attr->dump();
+}
+
+// Read a boolean (in fact unsigned 8 bit long) value
+bool readBool(FILE* stream, uint8_t& value)
+{
+       value = 0;
+       fpos_t pos;
+       if (fgetpos(stream, &pos) != 0)
+       {
+               return false;
+       }
+       uint8_t v;
+       if (fread(&v, 1, 1, stream) != 1)
+       {
+               (void) fsetpos(stream, &pos);
+               return false;
+       }
+       value = v;
+       return true;
+}
+
+// Read an unsigned 64 bit long value
+bool readULong(FILE* stream, uint64_t& value)
+{
+       value = 0;
+       fpos_t pos;
+       if (fgetpos(stream, &pos) != 0)
+       {
+               return false;
+       }
+       uint8_t v[8];
+       if (fread(v, 1, 8, stream) != 8)
+       {
+               (void) fsetpos(stream, &pos);
+               return false;
+       }
+       for (size_t i = 0; i < 8; i++)
+       {
+               value <<= 8;
+               value += v[i];
+       }
+       return true;
+}
+
+// Read a byte string (aka uint8_t vector) value
+bool readBytes(FILE* stream, std::vector<uint8_t>& value)
+{
+       size_t len = value.size();
+       fpos_t pos;
+       if (fgetpos(stream, &pos) != 0)
+       {
+               return false;
+       }
+       if (fread(&value[0], 1, len, stream) != len)
+       {
+               (void) fsetpos(stream, &pos);
+               return false;
+       }
+       return true;
+}
+
+// Read a map (aka Attribute vector) value
+bool readMap(FILE* stream, uint64_t len, std::vector<Attribute>& value)
+{
+       fpos_t pos;
+       if (fgetpos(stream, &pos) != 0)
+       {
+               return false;
+       }
+       while (len != 0)
+       {
+               Attribute attr;
+
+               if (len < 8)
+               {
+                       (void) fsetpos(stream, &pos);
+                       return false;
+               }
+               if (!readULong(stream, attr.type))
+               {
+                       (void) fsetpos(stream, &pos);
+                       return false;
+               }
+               len -= 8;
+
+               if (len < 8)
+               {
+                       (void) fsetpos(stream, &pos);
+                       return false;
+               }
+               if (!readULong(stream, attr.kind))
+               {
+                       (void) fsetpos(stream, &pos);
+                       return false;
+               }
+               len -= 8;
+
+               if (attr.kind == BOOLEAN_ATTR)
+               {
+                       if (len < 1)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       len -= 1;
+                       if (!readBool(stream, attr.boolValue))
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+               }
+               else if (attr.kind == ULONG_ATTR)
+               {
+                       if (len < 8)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       if (!readULong(stream, attr.ulongValue))
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       len -= 8;
+               }
+               else if (attr.kind == BYTES_ATTR)
+               {
+                       uint64_t size;
+                       if (len < 8)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       if (!readULong(stream, size))
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       len -= 8;
+
+                       if (len < size)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       attr.bytestrValue.resize((size_t)size);
+                       if (!readBytes(stream, attr.bytestrValue))
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       len -= size;
+               }
+               else if (attr.kind == MECHSET_ATTR)
+               {
+                       uint64_t size;
+                       if (len < 8)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       if (!readULong(stream, size))
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+                       len -= 8;
+
+                       if (len < size * 8)
+                       {
+                               (void) fsetpos(stream, &pos);
+                               return false;
+                       }
+
+                       for (unsigned long i = 0; i < size; i++)
+                       {
+                               uint64_t mech;
+                               if (!readULong(stream, mech))
+                               {
+                                       (void) fsetpos(stream, &pos);
+                                       return false;
+                               }
+                               attr.mechSetValue.insert(mech);
+                       }
+                       len -= size * 8;
+               }
+               else
+               {
+                       (void) fsetpos(stream, &pos);
+                       return false;
+               }
+
+               value.push_back(attr);
+       }
+
+       return true;
+}
+
+// Error case
+void corrupt(FILE* stream)
+{
+       uint8_t v;
+       for (size_t i = 0; i < 8; i++)
+       {
+               if (fread(&v, 1, 1, stream) != 1)
+               {
+                       if (ferror(stream))
+                       {
+                               printf("get an error...\n");
+                       }
+                       return;
+               }
+               if (i != 0)
+               {
+                       printf(" ");
+               }
+               printf("%02hhx", v);
+       }
+       if (fread(&v, 1, 1, stream) != 1)
+       {
+               if (ferror(stream))
+               {
+                       printf("\nget an error...\n");
+               }
+               return;
+       }
+       printf("...\n");
+}
+
+// Core function
+void dump(FILE* stream)
+{
+       uint64_t gen;
+       if (!readULong(stream, gen))
+       {
+               if (feof(stream))
+               {
+                       printf("empty file\n");
+               }
+               else
+               {
+                       corrupt(stream);
+               }
+               return;
+       }
+       dumpULong(gen);
+       printf("generation %lu\n", (unsigned long) gen);
+
+       while (!feof(stream))
+       {
+               uint64_t p11type;
+               if (!readULong(stream, p11type))
+               {
+                       corrupt(stream);
+                       return;
+               }
+               dumpULong(p11type);
+               if ((uint64_t)((uint32_t)p11type) != p11type)
+               {
+                       printf("overflow attribute type\n");
+               }
+               else
+               {
+                       dumpCKA((unsigned long) p11type, 48);
+                       printf("\n");
+               }
+
+               uint64_t disktype;
+               if (!readULong(stream, disktype))
+               {
+                       corrupt(stream);
+                       return;
+               }
+               dumpULong(disktype);
+               switch (disktype)
+               {
+               case BOOLEAN_ATTR:
+                       printf("boolean attribute\n");
+                       break;
+               case ULONG_ATTR:
+                       printf("unsigned long attribute\n");
+                       break;
+               case BYTES_ATTR:
+                       printf("byte string attribute\n");
+                       break;
+               case ATTRMAP_ATTR:
+                       printf("attribute map attribute\n");
+                       break;
+               case MECHSET_ATTR:
+                       printf("mechanism set attribute\n");
+                       break;
+               default:
+                       printf("unknown attribute format\n");
+                       break;
+               }
+
+               if (disktype == BOOLEAN_ATTR)
+               {
+                       uint8_t value;
+                       if (!readBool(stream, value))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpBool(value);
+                       printf("\n");
+               }
+               else if (disktype == ULONG_ATTR)
+               {
+                       uint64_t value;
+                       if (!readULong(stream, value))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpULong(value);
+                       dumpCKx(p11type, value, 48);
+                       printf("\n");
+               }
+               else if (disktype == BYTES_ATTR)
+               {
+                       uint64_t len;
+                       if (!readULong(stream, len))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpULong(len);
+                       if (len > MAX_BYTES)
+                       {
+                               printf("overflow length...\n");
+                               return;
+                       }
+                       printf("(length %lu)\n", (unsigned long) len);
+
+                       std::vector<uint8_t> value((size_t) len);
+                       if (!readBytes(stream, value))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpBytes(value);
+               }
+               else if (disktype == ATTRMAP_ATTR)
+               {
+                       uint64_t len;
+                       if (!readULong(stream, len))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpULong(len);
+                       if (len > MAX_BYTES)
+                       {
+                               printf("overflow length...\n");
+                               return;
+                       }
+                       printf("(length %lu)\n", (unsigned long) len);
+
+                       std::vector<Attribute> value;
+                       if (!readMap(stream, len, value))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpMap(value);
+               }
+               else if (disktype == MECHSET_ATTR)
+               {
+                       uint64_t len;
+                       if (!readULong(stream, len))
+                       {
+                               corrupt(stream);
+                               return;
+                       }
+                       dumpULong(len);
+                       if (len > MAX_BYTES)
+                       {
+                               printf("overflow length...\n");
+                               return;
+                       }
+                       printf("(length %lu)\n", (unsigned long) len);
+
+                       for (unsigned long i = 0; i < len; i++)
+                       {
+                               uint64_t mech;
+                               if (!readULong(stream, mech))
+                               {
+                                       corrupt(stream);
+                                       return;
+                               }
+                               dumpULong(mech);
+                               dumpCKM(mech, 48);
+                               printf("\n");
+                       }
+               }
+               else
+               {
+                       corrupt(stream);
+                       return;
+               }
+       }
+}
+
+// Display the usage
+void usage()
+{
+       printf("SoftHSM dump tool. From SoftHSM v2 object file.\n");
+       printf("Usage: softhsm2-dump-file path\n");
+}
+
+// The main function
+int main(int argc, char* argv[])
+{
+       FILE* stream;
+
+       if (argc != 2)
+       {
+               usage();
+               exit(0);
+       }
+
+       stream = fopen(argv[1], "r");
+       if (stream == NULL)
+       {
+               fprintf(stderr, "can't open object file %s\n", argv[1]);
+               exit(0);
+       }
+
+       printf("Dump of object file \"%s\"\n", argv[1]);
+       dump(stream);
+       exit(1);
+}
diff --git a/SoftHSMv2/src/bin/dump/tables.h b/SoftHSMv2/src/bin/dump/tables.h
new file mode 100644 (file)
index 0000000..76d64fb
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ tables.h
+
+ Tables from PKCS#11 specs.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_TABLES_H
+#define _SOFTHSM_V2_TABLES_H
+
+#include "OSAttributes.h"
+
+// Attribute types
+void fill_CKA_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKA_CLASS] = "CKA_CLASS";
+       t[CKA_TOKEN] = "CKA_TOKEN";
+       t[CKA_PRIVATE] = "CKA_PRIVATE";
+       t[CKA_LABEL] = "CKA_LABEL";
+       t[CKA_APPLICATION] = "CKA_APPLICATION";
+       t[CKA_VALUE] = "CKA_VALUE";
+       t[CKA_OBJECT_ID] = "CKA_OBJECT_ID";
+       t[CKA_CERTIFICATE_TYPE] = "CKA_CERTIFICATE_TYPE";
+       t[CKA_ISSUER] = "CKA_ISSUER";
+       t[CKA_SERIAL_NUMBER] = "CKA_SERIAL_NUMBER";
+       t[CKA_AC_ISSUER] = "CKA_AC_ISSUER";
+       t[CKA_OWNER] = "CKA_OWNER";
+       t[CKA_ATTR_TYPES] = "CKA_ATTR_TYPES";
+       t[CKA_TRUSTED] = "CKA_TRUSTED";
+       t[CKA_CERTIFICATE_CATEGORY] = "CKA_CERTIFICATE_CATEGORY";
+       t[CKA_JAVA_MIDP_SECURITY_DOMAIN] = "CKA_JAVA_MIDP_SECURITY_DOMAIN";
+       t[CKA_URL] = "CKA_URL";
+       t[CKA_HASH_OF_SUBJECT_PUBLIC_KEY] = "CKA_HASH_OF_SUBJECT_PUBLIC_KEY";
+       t[CKA_HASH_OF_ISSUER_PUBLIC_KEY] = "CKA_HASH_OF_ISSUER_PUBLIC_KEY";
+       t[CKA_NAME_HASH_ALGORITHM] = "CKA_NAME_HASH_ALGORITHM";
+       t[CKA_CHECK_VALUE] = "CKA_CHECK_VALUE";
+       t[CKA_KEY_TYPE] = "CKA_KEY_TYPE";
+       t[CKA_SUBJECT] = "CKA_SUBJECT";
+       t[CKA_ID] = "CKA_ID";
+       t[CKA_SENSITIVE] = "CKA_SENSITIVE";
+       t[CKA_ENCRYPT] = "CKA_ENCRYPT";
+       t[CKA_DECRYPT] = "CKA_DECRYPT";
+       t[CKA_WRAP] = "CKA_WRAP";
+       t[CKA_UNWRAP] = "CKA_UNWRAP";
+       t[CKA_SIGN] = "CKA_SIGN";
+       t[CKA_SIGN_RECOVER] = "CKA_SIGN_RECOVER";
+       t[CKA_VERIFY] = "CKA_VERIFY";
+       t[CKA_VERIFY_RECOVER] = "CKA_VERIFY_RECOVER";
+       t[CKA_DERIVE] = "CKA_DERIVE";
+       t[CKA_START_DATE] = "CKA_START_DATE";
+       t[CKA_END_DATE] = "CKA_END_DATE";
+       t[CKA_MODULUS] = "CKA_MODULUS";
+       t[CKA_MODULUS_BITS] = "CKA_MODULUS_BITS";
+       t[CKA_PUBLIC_EXPONENT] = "CKA_PUBLIC_EXPONENT";
+       t[CKA_PRIVATE_EXPONENT] = "CKA_PRIVATE_EXPONENT";
+       t[CKA_PRIME_1] = "CKA_PRIME_1";
+       t[CKA_PRIME_2] = "CKA_PRIME_2";
+       t[CKA_EXPONENT_1] = "CKA_EXPONENT_1";
+       t[CKA_EXPONENT_2] = "CKA_EXPONENT_2";
+       t[CKA_COEFFICIENT] = "CKA_COEFFICIENT";
+       t[CKA_PUBLIC_KEY_INFO] = "CKA_PUBLIC_KEY_INFO";
+       t[CKA_PRIME] = "CKA_PRIME";
+       t[CKA_SUBPRIME] = "CKA_SUBPRIME";
+       t[CKA_BASE] = "CKA_BASE";
+       t[CKA_PRIME_BITS] = "CKA_PRIME_BITS";
+       t[CKA_SUBPRIME_BITS] = "CKA_SUBPRIME_BITS";
+       t[CKA_VALUE_BITS] = "CKA_VALUE_BITS";
+       t[CKA_VALUE_LEN] = "CKA_VALUE_LEN";
+       t[CKA_EXTRACTABLE] = "CKA_EXTRACTABLE";
+       t[CKA_LOCAL] = "CKA_LOCAL";
+       t[CKA_NEVER_EXTRACTABLE] = "CKA_NEVER_EXTRACTABLE";
+       t[CKA_ALWAYS_SENSITIVE] = "CKA_ALWAYS_SENSITIVE";
+       t[CKA_KEY_GEN_MECHANISM] = "CKA_KEY_GEN_MECHANISM";
+       t[CKA_MODIFIABLE] = "CKA_MODIFIABLE";
+       t[CKA_COPYABLE] = "CKA_COPYABLE";
+       t[CKA_DESTROYABLE] = "CKA_DESTROYABLE";
+       t[CKA_EC_PARAMS] = "CKA_EC_PARAMS";
+       t[CKA_EC_POINT] = "CKA_EC_POINT";
+       t[CKA_SECONDARY_AUTH] = "CKA_SECONDARY_AUTH";
+       t[CKA_AUTH_PIN_FLAGS] = "CKA_AUTH_PIN_FLAGS";
+       t[CKA_ALWAYS_AUTHENTICATE] = "CKA_ALWAYS_AUTHENTICATE";
+       t[CKA_WRAP_WITH_TRUSTED] = "CKA_WRAP_WITH_TRUSTED";
+       t[CKA_WRAP_TEMPLATE] = "CKA_WRAP_TEMPLATE";
+       t[CKA_UNWRAP_TEMPLATE] = "CKA_UNWRAP_TEMPLATE";
+       t[CKA_DERIVE_TEMPLATE] = "CKA_DERIVE_TEMPLATE";
+       t[CKA_OTP_FORMAT] = "CKA_OTP_FORMAT";
+       t[CKA_OTP_LENGTH] = "CKA_OTP_LENGTH";
+       t[CKA_OTP_TIME_INTERVAL] = "CKA_OTP_TIME_INTERVAL";
+       t[CKA_OTP_USER_FRIENDLY_MODE] = "CKA_OTP_USER_FRIENDLY_MODE";
+       t[CKA_OTP_CHALLENGE_REQUIREMENT] = "CKA_OTP_CHALLENGE_REQUIREMENT";
+       t[CKA_OTP_TIME_REQUIREMENT] = "CKA_OTP_TIME_REQUIREMENT";
+       t[CKA_OTP_COUNTER_REQUIREMENT] = "CKA_OTP_COUNTER_REQUIREMENT";
+       t[CKA_OTP_PIN_REQUIREMENT] = "CKA_OTP_PIN_REQUIREMENT";
+       t[CKA_OTP_COUNTER] = "CKA_OTP_COUNTER";
+       t[CKA_OTP_TIME] = "CKA_OTP_TIME";
+       t[CKA_OTP_USER_IDENTIFIER] = "CKA_OTP_USER_IDENTIFIER";
+       t[CKA_OTP_SERVICE_IDENTIFIER] = "CKA_OTP_SERVICE_IDENTIFIER";
+       t[CKA_OTP_SERVICE_LOGO] = "CKA_OTP_SERVICE_LOGO";
+       t[CKA_OTP_SERVICE_LOGO_TYPE] = "CKA_OTP_SERVICE_LOGO_TYPE";
+       t[CKA_GOSTR3410_PARAMS] = "CKA_GOSTR3410_PARAMS";
+       t[CKA_GOSTR3411_PARAMS] = "CKA_GOSTR3411_PARAMS";
+       t[CKA_GOST28147_PARAMS] = "CKA_GOST28147_PARAMS";
+       t[CKA_HW_FEATURE_TYPE] = "CKA_HW_FEATURE_TYPE";
+       t[CKA_RESET_ON_INIT] = "CKA_RESET_ON_INIT";
+       t[CKA_HAS_RESET] = "CKA_HAS_RESET";
+       t[CKA_PIXEL_X] = "CKA_PIXEL_X";
+       t[CKA_PIXEL_Y] = "CKA_PIXEL_Y";
+       t[CKA_RESOLUTION] = "CKA_RESOLUTION";
+       t[CKA_CHAR_ROWS] = "CKA_CHAR_ROWS";
+       t[CKA_CHAR_COLUMNS] = "CKA_CHAR_COLUMNS";
+       t[CKA_COLOR] = "CKA_COLOR";
+       t[CKA_BITS_PER_PIXEL] = "CKA_BITS_PER_PIXEL";
+       t[CKA_CHAR_SETS] = "CKA_CHAR_SETS";
+       t[CKA_ENCODING_METHODS] = "CKA_ENCODING_METHODS";
+       t[CKA_MIME_TYPES] = "CKA_MIME_TYPES";
+       t[CKA_MECHANISM_TYPE] = "CKA_MECHANISM_TYPE";
+       t[CKA_REQUIRED_CMS_ATTRIBUTES] = "CKA_REQUIRED_CMS_ATTRIBUTES";
+       t[CKA_DEFAULT_CMS_ATTRIBUTES] = "CKA_DEFAULT_CMS_ATTRIBUTES";
+       t[CKA_SUPPORTED_CMS_ATTRIBUTES] = "CKA_SUPPORTED_CMS_ATTRIBUTES";
+       t[CKA_ALLOWED_MECHANISMS] = "CKA_ALLOWED_MECHANISMS";
+       // local extensions
+       t[CKA_VENDOR_SOFTHSM] = "CKA_VENDOR_SOFTHSM";
+       t[CKA_OS_TOKENLABEL] = "CKA_OS_TOKENLABEL";
+       t[CKA_OS_TOKENSERIAL] = "CKA_OS_TOKENSERIAL";
+       t[CKA_OS_TOKENFLAGS] = "CKA_OS_TOKENFLAGS";
+       t[CKA_OS_SOPIN] = "CKA_OS_SOPIN";
+       t[CKA_OS_USERPIN] = "CKA_OS_USERPIN";
+}
+
+void fill_CKM_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKM_RSA_PKCS_KEY_PAIR_GEN] = "CKM_RSA_PKCS_KEY_PAIR_GEN";
+       t[CKM_RSA_PKCS] = "CKM_RSA_PKCS";
+       t[CKM_RSA_9796] = "CKM_RSA_9796";
+       t[CKM_RSA_X_509] = "CKM_RSA_X_509";
+       t[CKM_MD2_RSA_PKCS] = "CKM_MD2_RSA_PKCS";
+       t[CKM_MD5_RSA_PKCS] = "CKM_MD5_RSA_PKCS";
+       t[CKM_SHA1_RSA_PKCS] = "CKM_SHA1_RSA_PKCS";
+       t[CKM_RIPEMD128_RSA_PKCS] = "CKM_RIPEMD128_RSA_PKCS";
+       t[CKM_RIPEMD160_RSA_PKCS] = "CKM_RIPEMD160_RSA_PKCS";
+       t[CKM_RSA_PKCS_OAEP] = "CKM_RSA_PKCS_OAEP";
+       t[CKM_RSA_X9_31_KEY_PAIR_GEN] = "CKM_RSA_X9_31_KEY_PAIR_GEN";
+       t[CKM_RSA_X9_31] = "CKM_RSA_X9_31";
+       t[CKM_SHA1_RSA_X9_31] = "CKM_SHA1_RSA_X9_31";
+       t[CKM_RSA_PKCS_PSS] = "CKM_RSA_PKCS_PSS";
+       t[CKM_SHA1_RSA_PKCS_PSS] = "CKM_SHA1_RSA_PKCS_PSS";
+       t[CKM_DSA_KEY_PAIR_GEN] = "CKM_DSA_KEY_PAIR_GEN";
+       t[CKM_DSA] = "CKM_DSA";
+       t[CKM_DSA_SHA1] = "CKM_DSA_SHA1";
+       t[CKM_DSA_SHA224] = "CKM_DSA_SHA224";
+       t[CKM_DSA_SHA256] = "CKM_DSA_SHA256";
+       t[CKM_DSA_SHA384] = "CKM_DSA_SHA384";
+       t[CKM_DSA_SHA512] = "CKM_DSA_SHA512";
+       t[CKM_DH_PKCS_KEY_PAIR_GEN] = "CKM_DH_PKCS_KEY_PAIR_GEN";
+       t[CKM_DH_PKCS_DERIVE] = "CKM_DH_PKCS_DERIVE";
+       t[CKM_X9_42_DH_KEY_PAIR_GEN] = "CKM_X9_42_DH_KEY_PAIR_GEN";
+       t[CKM_X9_42_DH_DERIVE] = "CKM_X9_42_DH_DERIVE";
+       t[CKM_X9_42_DH_HYBRID_DERIVE] = "CKM_X9_42_DH_HYBRID_DERIVE";
+       t[CKM_X9_42_MQV_DERIVE] = "CKM_X9_42_MQV_DERIVE";
+       t[CKM_SHA256_RSA_PKCS] = "CKM_SHA256_RSA_PKCS";
+       t[CKM_SHA384_RSA_PKCS] = "CKM_SHA384_RSA_PKCS";
+       t[CKM_SHA512_RSA_PKCS] = "CKM_SHA512_RSA_PKCS";
+       t[CKM_SHA256_RSA_PKCS_PSS] = "CKM_SHA256_RSA_PKCS_PSS";
+       t[CKM_SHA384_RSA_PKCS_PSS] = "CKM_SHA384_RSA_PKCS_PSS";
+       t[CKM_SHA512_RSA_PKCS_PSS] = "CKM_SHA512_RSA_PKCS_PSS";
+       t[CKM_SHA224_RSA_PKCS] = "CKM_SHA224_RSA_PKCS";
+       t[CKM_SHA224_RSA_PKCS_PSS] = "CKM_SHA224_RSA_PKCS_PSS";
+       t[CKM_SHA512_224] = "CKM_SHA512_224";
+       t[CKM_SHA512_224_HMAC] = "CKM_SHA512_224_HMAC";
+       t[CKM_SHA512_224_HMAC_GENERAL] = "CKM_SHA512_224_HMAC_GENERAL";
+       t[CKM_SHA512_224_KEY_DERIVATION] = "CKM_SHA512_224_KEY_DERIVATION";
+       t[CKM_SHA512_256] = "CKM_SHA512_256";
+       t[CKM_SHA512_256_HMAC] = "CKM_SHA512_256_HMAC";
+       t[CKM_SHA512_256_HMAC_GENERAL] = "CKM_SHA512_256_HMAC_GENERAL";
+       t[CKM_SHA512_256_KEY_DERIVATION] = "CKM_SHA512_256_KEY_DERIVATION";
+       t[CKM_SHA512_T] = "CKM_SHA512_T";
+       t[CKM_SHA512_T_HMAC] = "CKM_SHA512_T_HMAC";
+       t[CKM_SHA512_T_HMAC_GENERAL] = "CKM_SHA512_T_HMAC_GENERAL";
+       t[CKM_SHA512_T_KEY_DERIVATION] = "CKM_SHA512_T_KEY_DERIVATION";
+       t[CKM_RC2_KEY_GEN] = "CKM_RC2_KEY_GEN";
+       t[CKM_RC2_ECB] = "CKM_RC2_ECB";
+       t[CKM_RC2_CBC] = "CKM_RC2_CBC";
+       t[CKM_RC2_MAC] = "CKM_RC2_MAC";
+       t[CKM_RC2_MAC_GENERAL] = "CKM_RC2_MAC_GENERAL";
+       t[CKM_RC2_CBC_PAD] = "CKM_RC2_CBC_PAD";
+       t[CKM_RC4_KEY_GEN] = "CKM_RC4_KEY_GEN";
+       t[CKM_RC4] = "CKM_RC4";
+       t[CKM_DES_KEY_GEN] = "CKM_DES_KEY_GEN";
+       t[CKM_DES_ECB] = "CKM_DES_ECB";
+       t[CKM_DES_CBC] = "CKM_DES_CBC";
+       t[CKM_DES_MAC] = "CKM_DES_MAC";
+       t[CKM_DES_MAC_GENERAL] = "CKM_DES_MAC_GENERAL";
+       t[CKM_DES_CBC_PAD] = "CKM_DES_CBC_PAD";
+       t[CKM_DES2_KEY_GEN] = "CKM_DES2_KEY_GEN";
+       t[CKM_DES3_KEY_GEN] = "CKM_DES3_KEY_GEN";
+       t[CKM_DES3_ECB] = "CKM_DES3_ECB";
+       t[CKM_DES3_CBC] = "CKM_DES3_CBC";
+       t[CKM_DES3_MAC] = "CKM_DES3_MAC";
+       t[CKM_DES3_MAC_GENERAL] = "CKM_DES3_MAC_GENERAL";
+       t[CKM_DES3_CBC_PAD] = "CKM_DES3_CBC_PAD";
+       t[CKM_DES3_CMAC_GENERAL] = "CKM_DES3_CMAC_GENERAL";
+       t[CKM_DES3_CMAC] = "CKM_DES3_CMAC";
+       t[CKM_CDMF_KEY_GEN] = "CKM_CDMF_KEY_GEN";
+       t[CKM_CDMF_ECB] = "CKM_CDMF_ECB";
+       t[CKM_CDMF_CBC] = "CKM_CDMF_CBC";
+       t[CKM_CDMF_MAC] = "CKM_CDMF_MAC";
+       t[CKM_CDMF_MAC_GENERAL] = "CKM_CDMF_MAC_GENERAL";
+       t[CKM_CDMF_CBC_PAD] = "CKM_CDMF_CBC_PAD";
+       t[CKM_DES_OFB64] = "CKM_DES_OFB64";
+       t[CKM_DES_OFB8] = "CKM_DES_OFB8";
+       t[CKM_DES_CFB64] = "CKM_DES_CFB64";
+       t[CKM_DES_CFB8] = "CKM_DES_CFB8";
+       t[CKM_MD2] = "CKM_MD2";
+       t[CKM_MD2_HMAC] = "CKM_MD2_HMAC";
+       t[CKM_MD2_HMAC_GENERAL] = "CKM_MD2_HMAC_GENERAL";
+       t[CKM_MD5] = "CKM_MD5";
+       t[CKM_MD5_HMAC] = "CKM_MD5_HMAC";
+       t[CKM_MD5_HMAC_GENERAL] = "CKM_MD5_HMAC_GENERAL";
+       t[CKM_SHA_1] = "CKM_SHA_1";
+       t[CKM_SHA_1_HMAC] = "CKM_SHA_1_HMAC";
+       t[CKM_SHA_1_HMAC_GENERAL] = "CKM_SHA_1_HMAC_GENERAL";
+       t[CKM_RIPEMD128] = "CKM_RIPEMD128";
+       t[CKM_RIPEMD128_HMAC] = "CKM_RIPEMD128_HMAC";
+       t[CKM_RIPEMD128_HMAC_GENERAL] = "CKM_RIPEMD128_HMAC_GENERAL";
+       t[CKM_RIPEMD160] = "CKM_RIPEMD160";
+       t[CKM_RIPEMD160_HMAC] = "CKM_RIPEMD160_HMAC";
+       t[CKM_RIPEMD160_HMAC_GENERAL] = "CKM_RIPEMD160_HMAC_GENERAL";
+       t[CKM_SHA256] = "CKM_SHA256";
+       t[CKM_SHA256_HMAC] = "CKM_SHA256_HMAC";
+       t[CKM_SHA256_HMAC_GENERAL] = "CKM_SHA256_HMAC_GENERAL";
+       t[CKM_SHA224] = "CKM_SHA224";
+       t[CKM_SHA224_HMAC] = "CKM_SHA224_HMAC";
+       t[CKM_SHA224_HMAC_GENERAL] = "CKM_SHA224_HMAC_GENERAL";
+       t[CKM_SHA384] = "CKM_SHA384";
+       t[CKM_SHA384_HMAC] = "CKM_SHA384_HMAC";
+       t[CKM_SHA384_HMAC_GENERAL] = "CKM_SHA384_HMAC_GENERAL";
+       t[CKM_SHA512] = "CKM_SHA512";
+       t[CKM_SHA512_HMAC] = "CKM_SHA512_HMAC";
+       t[CKM_SHA512_HMAC_GENERAL] = "CKM_SHA512_HMAC_GENERAL";
+       t[CKM_SECURID_KEY_GEN] = "CKM_SECURID_KEY_GEN";
+       t[CKM_SECURID] = "CKM_SECURID";
+       t[CKM_HOTP_KEY_GEN] = "CKM_HOTP_KEY_GEN";
+       t[CKM_HOTP] = "CKM_HOTP";
+       t[CKM_ACTI] = "CKM_ACTI";
+       t[CKM_ACTI_KEY_GEN] = "CKM_ACTI_KEY_GEN";
+       t[CKM_CAST_KEY_GEN] = "CKM_CAST_KEY_GEN";
+       t[CKM_CAST_ECB] = "CKM_CAST_ECB";
+       t[CKM_CAST_CBC] = "CKM_CAST_CBC";
+       t[CKM_CAST_MAC] = "CKM_CAST_MAC";
+       t[CKM_CAST_MAC_GENERAL] = "CKM_CAST_MAC_GENERAL";
+       t[CKM_CAST_CBC_PAD] = "CKM_CAST_CBC_PAD";
+       t[CKM_CAST3_KEY_GEN] = "CKM_CAST3_KEY_GEN";
+       t[CKM_CAST3_ECB] = "CKM_CAST3_ECB";
+       t[CKM_CAST3_CBC] = "CKM_CAST3_CBC";
+       t[CKM_CAST3_MAC] = "CKM_CAST3_MAC";
+       t[CKM_CAST3_MAC_GENERAL] = "CKM_CAST3_MAC_GENERAL";
+       t[CKM_CAST3_CBC_PAD] = "CKM_CAST3_CBC_PAD";
+       t[CKM_CAST128_KEY_GEN] = "CKM_CAST128_KEY_GEN";
+       t[CKM_CAST128_ECB] = "CKM_CAST128_ECB";
+       t[CKM_CAST128_CBC] = "CKM_CAST128_CBC";
+       t[CKM_CAST128_MAC] = "CKM_CAST128_MAC";
+       t[CKM_CAST128_MAC_GENERAL] = "CKM_CAST128_MAC_GENERAL";
+       t[CKM_CAST128_CBC_PAD] = "CKM_CAST128_CBC_PAD";
+       t[CKM_RC5_KEY_GEN] = "CKM_RC5_KEY_GEN";
+       t[CKM_RC5_ECB] = "CKM_RC5_ECB";
+       t[CKM_RC5_CBC] = "CKM_RC5_CBC";
+       t[CKM_RC5_MAC] = "CKM_RC5_MAC";
+       t[CKM_RC5_MAC_GENERAL] = "CKM_RC5_MAC_GENERAL";
+       t[CKM_RC5_CBC_PAD] = "CKM_RC5_CBC_PAD";
+       t[CKM_IDEA_KEY_GEN] = "CKM_IDEA_KEY_GEN";
+       t[CKM_IDEA_ECB] = "CKM_IDEA_ECB";
+       t[CKM_IDEA_CBC] = "CKM_IDEA_CBC";
+       t[CKM_IDEA_MAC] = "CKM_IDEA_MAC";
+       t[CKM_IDEA_MAC_GENERAL] = "CKM_IDEA_MAC_GENERAL";
+       t[CKM_IDEA_CBC_PAD] = "CKM_IDEA_CBC_PAD";
+       t[CKM_GENERIC_SECRET_KEY_GEN] = "CKM_GENERIC_SECRET_KEY_GEN";
+       t[CKM_CONCATENATE_BASE_AND_KEY] = "CKM_CONCATENATE_BASE_AND_KEY";
+       t[CKM_CONCATENATE_BASE_AND_DATA] = "CKM_CONCATENATE_BASE_AND_DATA";
+       t[CKM_CONCATENATE_DATA_AND_BASE] = "CKM_CONCATENATE_DATA_AND_BASE";
+       t[CKM_XOR_BASE_AND_DATA] = "CKM_XOR_BASE_AND_DATA";
+       t[CKM_EXTRACT_KEY_FROM_KEY] = "CKM_EXTRACT_KEY_FROM_KEY";
+       t[CKM_SSL3_PRE_MASTER_KEY_GEN] = "CKM_SSL3_PRE_MASTER_KEY_GEN";
+       t[CKM_SSL3_MASTER_KEY_DERIVE] = "CKM_SSL3_MASTER_KEY_DERIVE";
+       t[CKM_SSL3_KEY_AND_MAC_DERIVE] = "CKM_SSL3_KEY_AND_MAC_DERIVE";
+       t[CKM_SSL3_MASTER_KEY_DERIVE_DH] = "CKM_SSL3_MASTER_KEY_DERIVE_DH";
+       t[CKM_TLS_PRE_MASTER_KEY_GEN] = "CKM_TLS_PRE_MASTER_KEY_GEN";
+       t[CKM_TLS_MASTER_KEY_DERIVE] = "CKM_TLS_MASTER_KEY_DERIVE";
+       t[CKM_TLS_KEY_AND_MAC_DERIVE] = "CKM_TLS_KEY_AND_MAC_DERIVE";
+       t[CKM_TLS_MASTER_KEY_DERIVE_DH] = "CKM_TLS_MASTER_KEY_DERIVE_DH";
+       t[CKM_TLS_PRF] = "CKM_TLS_PRF";
+       t[CKM_SSL3_MD5_MAC] = "CKM_SSL3_MD5_MAC";
+       t[CKM_SSL3_SHA1_MAC] = "CKM_SSL3_SHA1_MAC";
+       t[CKM_MD5_KEY_DERIVATION] = "CKM_MD5_KEY_DERIVATION";
+       t[CKM_MD2_KEY_DERIVATION] = "CKM_MD2_KEY_DERIVATION";
+       t[CKM_SHA1_KEY_DERIVATION] = "CKM_SHA1_KEY_DERIVATION";
+       t[CKM_SHA256_KEY_DERIVATION] = "CKM_SHA256_KEY_DERIVATION";
+       t[CKM_SHA384_KEY_DERIVATION] = "CKM_SHA384_KEY_DERIVATION";
+       t[CKM_SHA512_KEY_DERIVATION] = "CKM_SHA512_KEY_DERIVATION";
+       t[CKM_SHA224_KEY_DERIVATION] = "CKM_SHA224_KEY_DERIVATION";
+       t[CKM_PBE_MD2_DES_CBC] = "CKM_PBE_MD2_DES_CBC";
+       t[CKM_PBE_MD5_DES_CBC] = "CKM_PBE_MD5_DES_CBC";
+       t[CKM_PBE_MD5_CAST_CBC] = "CKM_PBE_MD5_CAST_CBC";
+       t[CKM_PBE_MD5_CAST3_CBC] = "CKM_PBE_MD5_CAST3_CBC";
+       t[CKM_PBE_MD5_CAST128_CBC] = "CKM_PBE_MD5_CAST128_CBC";
+       t[CKM_PBE_SHA1_CAST128_CBC] = "CKM_PBE_SHA1_CAST128_CBC";
+       t[CKM_PBE_SHA1_RC4_128] = "CKM_PBE_SHA1_RC4_128";
+       t[CKM_PBE_SHA1_RC4_40] = "CKM_PBE_SHA1_RC4_40";
+       t[CKM_PBE_SHA1_DES3_EDE_CBC] = "CKM_PBE_SHA1_DES3_EDE_CBC";
+       t[CKM_PBE_SHA1_DES2_EDE_CBC] = "CKM_PBE_SHA1_DES2_EDE_CBC";
+       t[CKM_PBE_SHA1_RC2_128_CBC] = "CKM_PBE_SHA1_RC2_128_CBC";
+       t[CKM_PBE_SHA1_RC2_40_CBC] = "CKM_PBE_SHA1_RC2_40_CBC";
+       t[CKM_PKCS5_PBKD2] = "CKM_PKCS5_PBKD2";
+       t[CKM_PBA_SHA1_WITH_SHA1_HMAC] = "CKM_PBA_SHA1_WITH_SHA1_HMAC";
+       t[CKM_WTLS_PRE_MASTER_KEY_GEN] = "CKM_WTLS_PRE_MASTER_KEY_GEN";
+       t[CKM_WTLS_MASTER_KEY_DERIVE] = "CKM_WTLS_MASTER_KEY_DERIVE";
+       t[CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC] = "CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC";
+       t[CKM_WTLS_PRF] = "CKM_WTLS_PRF";
+       t[CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE] = "CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE";
+       t[CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE] = "CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE";
+       t[CKM_TLS10_MAC_SERVER] = "CKM_TLS10_MAC_SERVER";
+       t[CKM_TLS10_MAC_CLIENT] = "CKM_TLS10_MAC_CLIENT";
+       t[CKM_TLS12_MAC] = "CKM_TLS12_MAC";
+       t[CKM_TLS12_KDF] = "CKM_TLS12_KDF";
+       t[CKM_TLS12_MASTER_KEY_DERIVE] = "CKM_TLS12_MASTER_KEY_DERIVE";
+       t[CKM_TLS12_KEY_AND_MAC_DERIVE] = "CKM_TLS12_KEY_AND_MAC_DERIVE";
+       t[CKM_TLS12_MASTER_KEY_DERIVE_DH] = "CKM_TLS12_MASTER_KEY_DERIVE_DH";
+       t[CKM_TLS12_KEY_SAFE_DERIVE] = "CKM_TLS12_KEY_SAFE_DERIVE";
+       t[CKM_TLS_MAC] = "CKM_TLS_MAC";
+       t[CKM_TLS_KDF] = "CKM_TLS_KDF";
+       t[CKM_KEY_WRAP_LYNKS] = "CKM_KEY_WRAP_LYNKS";
+       t[CKM_KEY_WRAP_SET_OAEP] = "CKM_KEY_WRAP_SET_OAEP";
+       t[CKM_CMS_SIG] = "CKM_CMS_SIG";
+       t[CKM_KIP_DERIVE] = "CKM_KIP_DERIVE";
+       t[CKM_KIP_WRAP] = "CKM_KIP_WRAP";
+       t[CKM_KIP_MAC] = "CKM_KIP_MAC";
+       t[CKM_CAMELLIA_KEY_GEN] = "CKM_CAMELLIA_KEY_GEN";
+       t[CKM_CAMELLIA_ECB] = "CKM_CAMELLIA_ECB";
+       t[CKM_CAMELLIA_CBC] = "CKM_CAMELLIA_CBC";
+       t[CKM_CAMELLIA_MAC] = "CKM_CAMELLIA_MAC";
+       t[CKM_CAMELLIA_MAC_GENERAL] = "CKM_CAMELLIA_MAC_GENERAL";
+       t[CKM_CAMELLIA_CBC_PAD] = "CKM_CAMELLIA_CBC_PAD";
+       t[CKM_CAMELLIA_ECB_ENCRYPT_DATA] = "CKM_CAMELLIA_ECB_ENCRYPT_DATA";
+       t[CKM_CAMELLIA_CBC_ENCRYPT_DATA] = "CKM_CAMELLIA_CBC_ENCRYPT_DATA";
+       t[CKM_CAMELLIA_CTR] = "CKM_CAMELLIA_CTR";
+       t[CKM_ARIA_KEY_GEN] = "CKM_ARIA_KEY_GEN";
+       t[CKM_ARIA_ECB] = "CKM_ARIA_ECB";
+       t[CKM_ARIA_CBC] = "CKM_ARIA_CBC";
+       t[CKM_ARIA_MAC] = "CKM_ARIA_MAC";
+       t[CKM_ARIA_MAC_GENERAL] = "CKM_ARIA_MAC_GENERAL";
+       t[CKM_ARIA_CBC_PAD] = "CKM_ARIA_CBC_PAD";
+       t[CKM_ARIA_ECB_ENCRYPT_DATA] = "CKM_ARIA_ECB_ENCRYPT_DATA";
+       t[CKM_ARIA_CBC_ENCRYPT_DATA] = "CKM_ARIA_CBC_ENCRYPT_DATA";
+       t[CKM_SEED_KEY_GEN] = "CKM_SEED_KEY_GEN";
+       t[CKM_SEED_ECB] = "CKM_SEED_ECB";
+       t[CKM_SEED_CBC] = "CKM_SEED_CBC";
+       t[CKM_SEED_MAC] = "CKM_SEED_MAC";
+       t[CKM_SEED_MAC_GENERAL] = "CKM_SEED_MAC_GENERAL";
+       t[CKM_SEED_CBC_PAD] = "CKM_SEED_CBC_PAD";
+       t[CKM_SEED_ECB_ENCRYPT_DATA] = "CKM_SEED_ECB_ENCRYPT_DATA";
+       t[CKM_SEED_CBC_ENCRYPT_DATA] = "CKM_SEED_CBC_ENCRYPT_DATA";
+       t[CKM_SKIPJACK_KEY_GEN] = "CKM_SKIPJACK_KEY_GEN";
+       t[CKM_SKIPJACK_ECB64] = "CKM_SKIPJACK_ECB64";
+       t[CKM_SKIPJACK_CBC64] = "CKM_SKIPJACK_CBC64";
+       t[CKM_SKIPJACK_OFB64] = "CKM_SKIPJACK_OFB64";
+       t[CKM_SKIPJACK_CFB64] = "CKM_SKIPJACK_CFB64";
+       t[CKM_SKIPJACK_CFB32] = "CKM_SKIPJACK_CFB32";
+       t[CKM_SKIPJACK_CFB16] = "CKM_SKIPJACK_CFB16";
+       t[CKM_SKIPJACK_CFB8] = "CKM_SKIPJACK_CFB8";
+       t[CKM_SKIPJACK_WRAP] = "CKM_SKIPJACK_WRAP";
+       t[CKM_SKIPJACK_PRIVATE_WRAP] = "CKM_SKIPJACK_PRIVATE_WRAP";
+       t[CKM_SKIPJACK_RELAYX] = "CKM_SKIPJACK_RELAYX";
+       t[CKM_KEA_KEY_PAIR_GEN] = "CKM_KEA_KEY_PAIR_GEN";
+       t[CKM_KEA_KEY_DERIVE] = "CKM_KEA_KEY_DERIVE";
+       t[CKM_FORTEZZA_TIMESTAMP] = "CKM_FORTEZZA_TIMESTAMP";
+       t[CKM_BATON_KEY_GEN] = "CKM_BATON_KEY_GEN";
+       t[CKM_BATON_ECB128] = "CKM_BATON_ECB128";
+       t[CKM_BATON_ECB96] = "CKM_BATON_ECB96";
+       t[CKM_BATON_CBC128] = "CKM_BATON_CBC128";
+       t[CKM_BATON_COUNTER] = "CKM_BATON_COUNTER";
+       t[CKM_BATON_SHUFFLE] = "CKM_BATON_SHUFFLE";
+       t[CKM_BATON_WRAP] = "CKM_BATON_WRAP";
+       t[CKM_EC_KEY_PAIR_GEN] = "CKM_EC_KEY_PAIR_GEN";
+       t[CKM_ECDSA] = "CKM_ECDSA";
+       t[CKM_ECDSA_SHA1] = "CKM_ECDSA_SHA1";
+       t[CKM_ECDSA_SHA224] = "CKM_ECDSA_SHA224";
+       t[CKM_ECDSA_SHA256] = "CKM_ECDSA_SHA256";
+       t[CKM_ECDSA_SHA384] = "CKM_ECDSA_SHA384";
+       t[CKM_ECDSA_SHA512] = "CKM_ECDSA_SHA512";
+       t[CKM_ECDH1_DERIVE] = "CKM_ECDH1_DERIVE";
+       t[CKM_ECDH1_COFACTOR_DERIVE] = "CKM_ECDH1_COFACTOR_DERIVE";
+       t[CKM_ECMQV_DERIVE] = "CKM_ECMQV_DERIVE";
+       t[CKM_ECDH_AES_KEY_WRAP] = "CKM_ECDH_AES_KEY_WRAP";
+       t[CKM_RSA_AES_KEY_WRAP] = "CKM_RSA_AES_KEY_WRAP";
+       t[CKM_JUNIPER_KEY_GEN] = "CKM_JUNIPER_KEY_GEN";
+       t[CKM_JUNIPER_ECB128] = "CKM_JUNIPER_ECB128";
+       t[CKM_JUNIPER_CBC128] = "CKM_JUNIPER_CBC128";
+       t[CKM_JUNIPER_COUNTER] = "CKM_JUNIPER_COUNTER";
+       t[CKM_JUNIPER_SHUFFLE] = "CKM_JUNIPER_SHUFFLE";
+       t[CKM_JUNIPER_WRAP] = "CKM_JUNIPER_WRAP";
+       t[CKM_FASTHASH] = "CKM_FASTHASH";
+       t[CKM_AES_KEY_GEN] = "CKM_AES_KEY_GEN";
+       t[CKM_AES_ECB] = "CKM_AES_ECB";
+       t[CKM_AES_CBC] = "CKM_AES_CBC";
+       t[CKM_AES_MAC] = "CKM_AES_MAC";
+       t[CKM_AES_MAC_GENERAL] = "CKM_AES_MAC_GENERAL";
+       t[CKM_AES_CBC_PAD] = "CKM_AES_CBC_PAD";
+       t[CKM_AES_CTR] = "CKM_AES_CTR";
+       t[CKM_AES_GCM] = "CKM_AES_GCM";
+       t[CKM_AES_CCM] = "CKM_AES_CCM";
+       t[CKM_AES_CTS] = "CKM_AES_CTS";
+       t[CKM_AES_CMAC] = "CKM_AES_CMAC";
+       t[CKM_AES_CMAC_GENERAL] = "CKM_AES_CMAC_GENERAL";
+       t[CKM_AES_XCBC_MAC] = "CKM_AES_XCBC_MAC";
+       t[CKM_AES_XCBC_MAC_96] = "CKM_AES_XCBC_MAC_96";
+       t[CKM_AES_GMAC] = "CKM_AES_GMAC";
+       t[CKM_BLOWFISH_KEY_GEN] = "CKM_BLOWFISH_KEY_GEN";
+       t[CKM_BLOWFISH_CBC] = "CKM_BLOWFISH_CBC";
+       t[CKM_TWOFISH_KEY_GEN] = "CKM_TWOFISH_KEY_GEN";
+       t[CKM_TWOFISH_CBC] = "CKM_TWOFISH_CBC";
+       t[CKM_BLOWFISH_CBC_PAD] = "CKM_BLOWFISH_CBC_PAD";
+       t[CKM_TWOFISH_CBC_PAD] = "CKM_TWOFISH_CBC_PAD";
+       t[CKM_DES_ECB_ENCRYPT_DATA] = "CKM_DES_ECB_ENCRYPT_DATA";
+       t[CKM_DES_CBC_ENCRYPT_DATA] = "CKM_DES_CBC_ENCRYPT_DATA";
+       t[CKM_DES3_ECB_ENCRYPT_DATA] = "CKM_DES3_ECB_ENCRYPT_DATA";
+       t[CKM_DES3_CBC_ENCRYPT_DATA] = "CKM_DES3_CBC_ENCRYPT_DATA";
+       t[CKM_AES_ECB_ENCRYPT_DATA] = "CKM_AES_ECB_ENCRYPT_DATA";
+       t[CKM_AES_CBC_ENCRYPT_DATA] = "CKM_AES_CBC_ENCRYPT_DATA";
+       t[CKM_GOSTR3410_KEY_PAIR_GEN] = "CKM_GOSTR3410_KEY_PAIR_GEN";
+       t[CKM_GOSTR3410] = "CKM_GOSTR3410";
+       t[CKM_GOSTR3410_WITH_GOSTR3411] = "CKM_GOSTR3410_WITH_GOSTR3411";
+       t[CKM_GOSTR3410_KEY_WRAP] = "CKM_GOSTR3410_KEY_WRAP";
+       t[CKM_GOSTR3410_DERIVE] = "CKM_GOSTR3410_DERIVE";
+       t[CKM_GOSTR3411] = "CKM_GOSTR3411";
+       t[CKM_GOSTR3411_HMAC] = "CKM_GOSTR3411_HMAC";
+       t[CKM_GOST28147_KEY_GEN] = "CKM_GOST28147_KEY_GEN";
+       t[CKM_GOST28147_ECB] = "CKM_GOST28147_ECB";
+       t[CKM_GOST28147] = "CKM_GOST28147";
+       t[CKM_GOST28147_MAC] = "CKM_GOST28147_MAC";
+       t[CKM_GOST28147_KEY_WRAP] = "CKM_GOST28147_KEY_WRAP";
+       t[CKM_DSA_PARAMETER_GEN] = "CKM_DSA_PARAMETER_GEN";
+       t[CKM_DH_PKCS_PARAMETER_GEN] = "CKM_DH_PKCS_PARAMETER_GEN";
+       t[CKM_X9_42_DH_PARAMETER_GEN] = "CKM_X9_42_DH_PARAMETER_GEN";
+       t[CKM_DSA_PROBABLISTIC_PARAMETER_GEN] = "CKM_DSA_PROBABLISTIC_PARAMETER_GEN";
+       t[CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN] = "CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN";
+       t[CKM_AES_OFB] = "CKM_AES_OFB";
+       t[CKM_AES_CFB64] = "CKM_AES_CFB64";
+       t[CKM_AES_CFB8] = "CKM_AES_CFB8";
+       t[CKM_AES_CFB128] = "CKM_AES_CFB128";
+       t[CKM_AES_CFB1] = "CKM_AES_CFB1";
+       t[CKM_AES_KEY_WRAP] = "CKM_AES_KEY_WRAP";
+       t[CKM_AES_KEY_WRAP_PAD] = "CKM_AES_KEY_WRAP_PAD";
+       t[CKM_RSA_PKCS_TPM_1_1] = "CKM_RSA_PKCS_TPM_1_1";
+       t[CKM_RSA_PKCS_OAEP_TPM_1_1] = "CKM_RSA_PKCS_OAEP_TPM_1_1";
+}
+
+void fill_CKO_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKO_DATA] = "CKO_DATA";
+       t[CKO_CERTIFICATE] = "CKO_CERTIFICATE";
+       t[CKO_PUBLIC_KEY] = "CKO_PUBLIC_KEY";
+       t[CKO_PRIVATE_KEY] = "CKO_PRIVATE_KEY";
+       t[CKO_SECRET_KEY] = "CKO_SECRET_KEY";
+       t[CKO_HW_FEATURE] = "CKO_HW_FEATURE";
+       t[CKO_DOMAIN_PARAMETERS] = "CKO_DOMAIN_PARAMETERS";
+       t[CKO_MECHANISM] = "CKO_MECHANISM";
+       t[CKO_OTP_KEY] = "CKO_OTP_KEY";
+}
+
+void fill_CKH_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKH_MONOTONIC_COUNTER] = "CKH_MONOTONIC_COUNTER";
+       t[CKH_CLOCK] = "CKH_CLOCK";
+       t[CKH_USER_INTERFACE] = "CKH_USER_INTERFACE";
+}
+
+void fill_CKK_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKK_RSA] = "CKK_RSA";
+       t[CKK_DSA] = "CKK_DSA";
+       t[CKK_DH] = "CKK_DH";
+       t[CKK_EC] = "CKK_EC";
+       t[CKK_X9_42_DH] = "CKK_X9_42_DH";
+       t[CKK_KEA] = "CKK_KEA";
+       t[CKK_GENERIC_SECRET] = "CKK_GENERIC_SECRET";
+       t[CKK_RC2] = "CKK_RC2";
+       t[CKK_RC4] = "CKK_RC4";
+       t[CKK_DES] = "CKK_DES";
+       t[CKK_DES2] = "CKK_DES2";
+       t[CKK_DES3] = "CKK_DES3";
+       t[CKK_CAST] = "CKK_CAST";
+       t[CKK_CAST3] = "CKK_CAST3";
+       t[CKK_CAST128] = "CKK_CAST128";
+       t[CKK_RC5] = "CKK_RC5";
+       t[CKK_IDEA] = "CKK_IDEA";
+       t[CKK_SKIPJACK] = "CKK_SKIPJACK";
+       t[CKK_BATON] = "CKK_BATON";
+       t[CKK_JUNIPER] = "CKK_JUNIPER";
+       t[CKK_CDMF] = "CKK_CDMF";
+       t[CKK_AES] = "CKK_AES";
+       t[CKK_BLOWFISH] = "CKK_BLOWFISH";
+       t[CKK_TWOFISH] = "CKK_TWOFISH";
+       t[CKK_SECURID] = "CKK_SECURID";
+       t[CKK_HOTP] = "CKK_HOTP";
+       t[CKK_ACTI] = "CKK_ACTI";
+       t[CKK_CAMELLIA] = "CKK_CAMELLIA";
+       t[CKK_ARIA] = "CKK_ARIA";
+       t[CKK_MD5_HMAC] = "CKK_MD5_HMAC";
+       t[CKK_SHA_1_HMAC] = "CKK_SHA_1_HMAC";
+       t[CKK_RIPEMD128_HMAC] = "CKK_RIPEMD128_HMAC";
+       t[CKK_RIPEMD160_HMAC] = "CKK_RIPEMD160_HMAC";
+       t[CKK_SHA256_HMAC] = "CKK_SHA256_HMAC";
+       t[CKK_SHA384_HMAC] = "CKK_SHA384_HMAC";
+       t[CKK_SHA512_HMAC] = "CKK_SHA512_HMAC";
+       t[CKK_SHA224_HMAC] = "CKK_SHA224_HMAC";
+       t[CKK_SEED] = "CKK_SEED";
+       t[CKK_GOSTR3410] = "CKK_GOSTR3410";
+       t[CKK_GOSTR3411] = "CKK_GOSTR3411";
+       t[CKK_GOST28147] = "CKK_GOST28147";
+}
+
+void fill_CKC_table(std::map<unsigned long, std::string> &t)
+{
+       t[CKC_X_509] = "CKC_X_509";
+       t[CKC_X_509_ATTR_CERT] = "CKC_X_509_ATTR_CERT";
+       t[CKC_WTLS] = "CKC_WTLS";
+       t[CKC_OPENPGP] = "CKC_OPENPGP";
+}
+
+#endif // !_SOFTHSM_V2_TABLES_H
diff --git a/SoftHSMv2/src/bin/keyconv/Makefile.am b/SoftHSMv2/src/bin/keyconv/Makefile.am
new file mode 100644 (file)
index 0000000..b4268c2
--- /dev/null
@@ -0,0 +1,26 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/../../lib/crypto \
+                               @CRYPTO_INCLUDES@
+
+dist_man_MANS =                        softhsm2-keyconv.1
+
+bin_PROGRAMS =                 softhsm2-keyconv
+
+softhsm2_keyconv_SOURCES =     softhsm2-keyconv.cpp \
+                               base64.c
+softhsm2_keyconv_LDADD =       @CRYPTO_LIBS@
+
+# Compile with OpenSSL support
+if WITH_OPENSSL
+softhsm2_keyconv_SOURCES +=    softhsm2-keyconv-ossl.cpp \
+                               ../../lib/crypto/OSSLComp.cpp
+endif
+
+# Compile with Botan support
+if WITH_BOTAN
+softhsm2_keyconv_SOURCES +=    softhsm2-keyconv-botan.cpp
+endif
+
+EXTRA_DIST =                   $(srcdir)/*.h \
+                               $(srcdir)/*.cpp
diff --git a/SoftHSMv2/src/bin/keyconv/base64.c b/SoftHSMv2/src/bin/keyconv/base64.c
new file mode 100644 (file)
index 0000000..3eb1201
--- /dev/null
@@ -0,0 +1,311 @@
+/* $OpenBSD: base64.c,v 1.3 2002/06/09 08:13:07 todd Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$ISC: base64.c,v 8.6 1999/01/08 19:25:18 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#include <sys/socket.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+   The following encoding technique is taken from RFC 1521 by Borenstein
+   and Freed.  It is reproduced here in a slightly edited form for
+   convenience.
+
+   A 65-character subset of US-ASCII is used, enabling 6 bits to be
+   represented per printable character. (The extra 65th character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 24-bit groups of input bits as output
+   strings of 4 encoded characters. Proceeding from left to right, a
+   24-bit input group is formed by concatenating 3 8-bit input groups.
+   These 24 bits are then treated as 4 concatenated 6-bit groups, each
+   of which is translated into a single digit in the base64 alphabet.
+
+   Each 6-bit group is used as an index into an array of 64 printable
+   characters. The character referenced by the index is placed in the
+   output string.
+
+                         Table 1: The Base64 Alphabet
+
+      Value Encoding  Value Encoding  Value Encoding  Value Encoding
+          0 A            17 R            34 i            51 z
+          1 B            18 S            35 j            52 0
+          2 C            19 T            36 k            53 1
+          3 D            20 U            37 l            54 2
+          4 E            21 V            38 m            55 3
+          5 F            22 W            39 n            56 4
+          6 G            23 X            40 o            57 5
+          7 H            24 Y            41 p            58 6
+          8 I            25 Z            42 q            59 7
+          9 J            26 a            43 r            60 8
+         10 K            27 b            44 s            61 9
+         11 L            28 c            45 t            62 +
+         12 M            29 d            46 u            63 /
+         13 N            30 e            47 v
+         14 O            31 f            48 w         (pad) =
+         15 P            32 g            49 x
+         16 Q            33 h            50 y
+
+   Special processing is performed if fewer than 24 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a quantity.  When fewer than 24 input
+   bits are available in an input group, zero bits are added (on the
+   right) to form an integral number of 6-bit groups.  Padding at the
+   end of the data is performed using the '=' character.
+
+   Since all base64 input is an integral number of octets, only the
+         -------------------------------------------------
+   following cases can arise:
+
+       (1) the final quantum of encoding input is an integral
+           multiple of 24 bits; here, the final unit of encoded
+          output will be an integral multiple of 4 characters
+          with no "=" padding,
+       (2) the final quantum of encoding input is exactly 8 bits;
+           here, the final unit of encoded output will be two
+          characters followed by two "=" padding characters, or
+       (3) the final quantum of encoding input is exactly 16 bits;
+           here, the final unit of encoded output will be three
+          characters followed by one "=" padding character.
+   */
+
+int
+b64_ntop(unsigned char const *src, size_t srclength, char *target, size_t targsize) {
+       size_t datalength = 0;
+       unsigned char input[3];
+       unsigned char output[4];
+       size_t i;
+
+       while (2 < srclength) {
+               input[0] = *src++;
+               input[1] = *src++;
+               input[2] = *src++;
+               srclength -= 3;
+
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               output[3] = input[2] & 0x3f;
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+               Assert(output[3] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               target[datalength++] = Base64[output[2]];
+               target[datalength++] = Base64[output[3]];
+       }
+
+       /* Now we worry about padding. */
+       if (0 != srclength) {
+               /* Get what's left. */
+               input[0] = input[1] = input[2] = '\0';
+               for (i = 0; i < srclength; i++)
+                       input[i] = *src++;
+       
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               if (srclength == 1)
+                       target[datalength++] = Pad64;
+               else
+                       target[datalength++] = Base64[output[2]];
+               target[datalength++] = Pad64;
+       }
+       if (datalength >= targsize)
+               return (-1);
+       target[datalength] = '\0';      /* Returned value doesn't count \0. */
+       return (datalength);
+}
+
+/* skips all whitespace anywhere.
+   converts characters, four at a time, starting at (or after)
+   src from base - 64 numbers into three 8 bit bytes in the target area.
+   it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(char const *src, unsigned char *target, size_t targsize) {
+       int tarindex, state, ch;
+       char *pos;
+
+       state = 0;
+       tarindex = 0;
+
+       while ((ch = *src++) != '\0') {
+               if (isspace(ch))        /* Skip whitespace anywhere. */
+                       continue;
+
+               if (ch == Pad64)
+                       break;
+
+               pos = strchr(Base64, ch);
+               if (pos == 0)           /* A non-base64 character. */
+                       return (-1);
+
+               switch (state) {
+               case 0:
+                       if (target) {
+                               if ((size_t)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] = (pos - Base64) << 2;
+                       }
+                       state = 1;
+                       break;
+               case 1:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 4;
+                               target[tarindex+1]  = ((pos - Base64) & 0x0f)
+                                                       << 4 ;
+                       }
+                       tarindex++;
+                       state = 2;
+                       break;
+               case 2:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 2;
+                               target[tarindex+1]  = ((pos - Base64) & 0x03)
+                                                       << 6;
+                       }
+                       tarindex++;
+                       state = 3;
+                       break;
+               case 3:
+                       if (target) {
+                               if ((size_t)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] |= (pos - Base64);
+                       }
+                       tarindex++;
+                       state = 0;
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       /*
+        * We are done decoding Base-64 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+
+       if (ch == Pad64) {              /* We got a pad char. */
+               ch = *src++;            /* Skip it, get next. */
+               switch (state) {
+               case 0:         /* Invalid = in first position */
+               case 1:         /* Invalid = in second position */
+                       return (-1);
+
+               case 2:         /* Valid, means one byte of info */
+                       /* Skip any number of spaces. */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (ch != Pad64)
+                               return (-1);
+                       ch = *src++;            /* Skip the = */
+                       /* Fall through to "single trailing =" case. */
+                       /* FALLTHROUGH */
+
+               case 3:         /* Valid, means two bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       return (-1);
+
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target && target[tarindex] != 0)
+                               return (-1);
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       return (-1);
+       }
+
+       return (tarindex);
+}
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp
new file mode 100644 (file)
index 0000000..cb5700f
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-keyconv-botan.cpp
+
+ Code specific for Botan
+ *****************************************************************************/
+
+#include <config.h>
+#define KEYCONV_BOTAN
+#include "softhsm2-keyconv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+#include <botan/init.h>
+#include <botan/auto_rng.h>
+#include <botan/pkcs8.h>
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#include <botan/bigint.h>
+#include <botan/version.h>
+
+// Init Botan
+void crypto_init()
+{
+       Botan::LibraryInitializer::initialize();
+}
+
+// Final Botan
+void crypto_final()
+{
+       Botan::LibraryInitializer::deinitialize();
+}
+
+// Save the RSA key as a PKCS#8 file
+int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey)
+{
+       int result = 0;
+       Botan::Private_Key* priv_key = NULL;
+       Botan::AutoSeeded_RNG* rng = NULL;
+       Botan::BigInt bigE, bigP, bigQ, bigN, bigD;
+
+       // See if the key material was found.
+       if
+       (
+               pkey[TAG_MODULUS].size <= 0 ||
+               pkey[TAG_PUBEXP].size <= 0 ||
+                pkey[TAG_PRIVEXP].size <= 0 ||
+               pkey[TAG_PRIME1].size <= 0 ||
+               pkey[TAG_PRIME2].size <= 0
+       )
+       {
+               fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n");
+               return 1;
+       }
+
+       bigE = Botan::BigInt((Botan::byte*)pkey[TAG_PUBEXP].big,  pkey[TAG_PUBEXP].size);
+       bigP = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME1].big,  pkey[TAG_PRIME1].size);
+       bigQ = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME2].big,  pkey[TAG_PRIME2].size);
+       bigN = Botan::BigInt((Botan::byte*)pkey[TAG_MODULUS].big, pkey[TAG_MODULUS].size);
+       bigD = Botan::BigInt((Botan::byte*)pkey[TAG_PRIVEXP].big, pkey[TAG_PRIVEXP].size);
+
+       rng = new Botan::AutoSeeded_RNG();
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+               priv_key = new Botan::RSA_PrivateKey(bigP, bigQ, bigE, bigD, bigN);
+#else
+               priv_key = new Botan::RSA_PrivateKey(*rng, bigP, bigQ, bigE, bigD, bigN);
+#endif
+       }
+       catch(std::exception& e)
+       {
+               fprintf(stderr, "%s\n", e.what());
+               fprintf(stderr, "ERROR: Could not extract the private key from the file.\n");
+               delete rng;
+               return 1;
+       }
+
+       std::ofstream priv_file(out_path);
+       if (!priv_file.is_open())
+       {
+               fprintf(stderr, "ERROR: Could not open file for output.\n");
+               delete rng;
+               delete priv_key;
+               return 1;
+       }
+
+       try
+       {
+               if (file_pin == NULL)
+               {
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key);
+               }
+               else
+               {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, std::chrono::milliseconds(300), "PBE-PKCS5v15(MD5,DES/CBC)");
+#else
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, "PBE-PKCS5v15(MD5,DES/CBC)");
+#endif
+               }
+
+               printf("The key has been written to %s\n", out_path);
+       }
+       catch(std::exception& e)
+       {
+               fprintf(stderr, "%s\n", e.what());
+               fprintf(stderr, "ERROR: Could not write to file.\n");
+               result = 1;
+       }
+
+       delete rng;
+       delete priv_key;
+       priv_file.close();
+
+       return result;
+}
+
+// Save the DSA key as a PKCS#8 file
+int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey)
+{
+       int result = 0;
+       Botan::Private_Key* priv_key = NULL;
+       Botan::AutoSeeded_RNG* rng = NULL;
+       Botan::BigInt bigDP, bigDQ, bigDG, bigDX;
+
+       // See if the key material was found.
+       if
+       (
+               pkey[TAG_PRIME].size <= 0 ||
+               pkey[TAG_SUBPRIME].size <= 0 ||
+               pkey[TAG_BASE].size <= 0 ||
+               pkey[TAG_PRIVVAL].size <= 0
+       )
+       {
+               fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n");
+               return 1;
+       }
+
+       bigDP = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME].big,    pkey[TAG_PRIME].size);
+       bigDQ = Botan::BigInt((Botan::byte*)pkey[TAG_SUBPRIME].big, pkey[TAG_SUBPRIME].size);
+       bigDG = Botan::BigInt((Botan::byte*)pkey[TAG_BASE].big,     pkey[TAG_BASE].size);
+       bigDX = Botan::BigInt((Botan::byte*)pkey[TAG_PRIVVAL].big,  pkey[TAG_PRIVVAL].size);
+
+       rng = new Botan::AutoSeeded_RNG();
+
+       try
+       {
+               priv_key = new Botan::DSA_PrivateKey(*rng, Botan::DL_Group(bigDP, bigDQ, bigDG), bigDX);
+       }
+       catch (std::exception& e)
+       {
+               fprintf(stderr, "%s\n", e.what());
+               fprintf(stderr, "ERROR: Could not extract the private key from the file.\n");
+               delete rng;
+               return 1;
+       }
+
+       std::ofstream priv_file(out_path);
+       if (!priv_file.is_open())
+       {
+               fprintf(stderr, "ERROR: Could not open file for output.\n");
+               delete rng;
+               delete priv_key;
+               return 1;
+       }
+
+       try
+       {
+               if (file_pin == NULL)
+               {
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key);
+               }
+               else
+               {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, std::chrono::milliseconds(300), "PBE-PKCS5v15(MD5,DES/CBC)");
+#else
+                       priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, "PBE-PKCS5v15(MD5,DES/CBC)");
+#endif
+               }
+
+               printf("The key has been written to %s\n", out_path);
+       }
+       catch (std::exception& e)
+       {
+               fprintf(stderr, "%s\n", e.what());
+               fprintf(stderr, "ERROR: Could not write to file.\n");
+               result = 1;
+       }
+
+       delete rng;
+       delete priv_key;
+       priv_file.close();
+
+       return result;
+}
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp
new file mode 100644 (file)
index 0000000..a5cd8eb
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-keyconv-ossl.cpp
+
+ Code specific for OpenSSL
+ *****************************************************************************/
+
+#include <config.h>
+#define KEYCONV_OSSL
+#include "softhsm2-keyconv.h"
+#include "OSSLComp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+
+// Init OpenSSL
+void crypto_init()
+{
+       OpenSSL_add_all_algorithms();
+#ifdef WITH_FIPS
+       if (!FIPS_mode_set(1))
+       {
+               fprintf(stderr, "ERROR: can't enter into FIPS mode.\n");
+               exit(0);
+       }
+#endif
+}
+
+// Final OpenSSL
+void crypto_final()
+{
+       EVP_cleanup();
+       CRYPTO_cleanup_all_ex_data();
+}
+
+// Save the RSA key as a PKCS#8 file
+int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey)
+{
+       RSA* rsa = NULL;
+       EVP_PKEY* ossl_pkey = NULL;
+       PKCS8_PRIV_KEY_INFO* p8inf = NULL;
+       BIO* out = NULL;
+       X509_SIG* p8 = NULL;
+       int result = 0;
+
+       // See if the key material was found.
+       if
+       (
+               pkey[TAG_MODULUS].size <= 0 ||
+               pkey[TAG_PUBEXP].size <= 0 ||
+               pkey[TAG_PRIVEXP].size <= 0 ||
+               pkey[TAG_PRIME1].size <= 0 ||
+               pkey[TAG_PRIME2].size <= 0 ||
+               pkey[TAG_EXP1].size <= 0 ||
+               pkey[TAG_EXP2].size <= 0 ||
+               pkey[TAG_COEFF].size <= 0
+       )
+       {
+               fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n");
+               return 1;
+       }
+
+       rsa = RSA_new();
+       BIGNUM* bn_p =    BN_bin2bn((unsigned char*)pkey[TAG_PRIME1].big,  pkey[TAG_PRIME1].size, NULL);
+       BIGNUM* bn_q =    BN_bin2bn((unsigned char*)pkey[TAG_PRIME2].big,  pkey[TAG_PRIME2].size, NULL);
+       BIGNUM* bn_d =    BN_bin2bn((unsigned char*)pkey[TAG_PRIVEXP].big, pkey[TAG_PRIVEXP].size, NULL);
+       BIGNUM* bn_n =    BN_bin2bn((unsigned char*)pkey[TAG_MODULUS].big, pkey[TAG_MODULUS].size, NULL);
+       BIGNUM* bn_e =    BN_bin2bn((unsigned char*)pkey[TAG_PUBEXP].big,  pkey[TAG_PUBEXP].size, NULL);
+       BIGNUM* bn_dmp1 = BN_bin2bn((unsigned char*)pkey[TAG_EXP1].big,    pkey[TAG_EXP1].size, NULL);
+       BIGNUM* bn_dmq1 = BN_bin2bn((unsigned char*)pkey[TAG_EXP2].big,    pkey[TAG_EXP2].size, NULL);
+       BIGNUM* bn_iqmp = BN_bin2bn((unsigned char*)pkey[TAG_COEFF].big,   pkey[TAG_COEFF].size, NULL);
+       RSA_set0_factors(rsa, bn_p, bn_q);
+       RSA_set0_crt_params(rsa, bn_dmp1, bn_dmq1, bn_iqmp);
+       RSA_set0_key(rsa, bn_n, bn_e, bn_d);
+
+       ossl_pkey = EVP_PKEY_new();
+
+       // Convert RSA to EVP_PKEY
+       if (!EVP_PKEY_set1_RSA(ossl_pkey, rsa))
+       {
+               fprintf(stderr, "ERROR: Could not convert RSA key to EVP_PKEY.\n");
+               RSA_free(rsa);
+               EVP_PKEY_free(ossl_pkey);
+               return 1;
+       }
+       RSA_free(rsa);
+
+       // Convert EVP_PKEY to PKCS#8
+       if (!(p8inf = EVP_PKEY2PKCS8(ossl_pkey)))
+       {
+               fprintf(stderr, "ERROR: Could not convert EVP_PKEY to PKCS#8.\n");
+               EVP_PKEY_free(ossl_pkey);
+               return 1;
+       }
+       EVP_PKEY_free(ossl_pkey);
+
+       // Open output file
+       if (!(out = BIO_new_file (out_path, "wb")))
+       {
+               fprintf(stderr, "ERROR: Could not open the output file.\n");
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return 1;
+       }
+
+       // Write to disk
+       if (file_pin == NULL)
+       {
+               PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
+               printf("The key has been written to %s\n", out_path);
+       }
+       else
+       {
+               // Encrypt p8
+               if (!(p8 = PKCS8_encrypt(NID_pbeWithMD5AndDES_CBC, NULL,
+                                       file_pin, strlen(file_pin), NULL, 
+                                       0, PKCS12_DEFAULT_ITER, p8inf)))
+               {
+                       fprintf(stderr, "ERROR: Could not encrypt the PKCS#8 file\n");
+                       result = 1;
+               }
+               else
+               {
+                       PEM_write_bio_PKCS8(out, p8);
+                       X509_SIG_free(p8);
+                       printf("The key has been written to %s\n", out_path);
+               }
+       }
+
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       BIO_free_all(out);
+
+       return result;
+}
+
+// Save the DSA key as a PKCS#8 file
+int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey)
+{
+       DSA* dsa = NULL;
+       EVP_PKEY* ossl_pkey = NULL;
+       PKCS8_PRIV_KEY_INFO* p8inf = NULL;
+       BIO* out = NULL;
+       X509_SIG* p8 = NULL;
+       int result = 0;
+
+       // See if the key material was found.
+       if
+       (
+               pkey[TAG_PRIME].size <= 0 ||
+               pkey[TAG_SUBPRIME].size <= 0 ||
+               pkey[TAG_BASE].size <= 0 ||
+               pkey[TAG_PRIVVAL].size <= 0 ||
+               pkey[TAG_PUBVAL].size <= 0
+       )
+       {
+               fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n");
+               return 1;
+       }
+
+       dsa = DSA_new();
+       BIGNUM* bn_p =        BN_bin2bn((unsigned char*)pkey[TAG_PRIME].big,    pkey[TAG_PRIME].size, NULL);
+       BIGNUM* bn_q =        BN_bin2bn((unsigned char*)pkey[TAG_SUBPRIME].big, pkey[TAG_SUBPRIME].size, NULL);
+       BIGNUM* bn_g =        BN_bin2bn((unsigned char*)pkey[TAG_BASE].big,     pkey[TAG_BASE].size, NULL);
+       BIGNUM* bn_priv_key = BN_bin2bn((unsigned char*)pkey[TAG_PRIVVAL].big,  pkey[TAG_PRIVVAL].size, NULL);
+       BIGNUM* bn_pub_key =  BN_bin2bn((unsigned char*)pkey[TAG_PUBVAL].big,   pkey[TAG_PUBVAL].size, NULL);
+
+       DSA_set0_pqg(dsa, bn_p, bn_q, bn_g);
+       DSA_set0_key(dsa, bn_pub_key, bn_priv_key);
+
+       ossl_pkey = EVP_PKEY_new();
+
+       // Convert DSA to EVP_PKEY
+       if (!EVP_PKEY_set1_DSA(ossl_pkey, dsa))
+       {
+               fprintf(stderr, "ERROR: Could not convert DSA key to EVP_PKEY.\n");
+               DSA_free(dsa);
+               EVP_PKEY_free(ossl_pkey);
+               return 1;
+       }
+       DSA_free(dsa);
+
+       // Convert EVP_PKEY to PKCS#8
+       if (!(p8inf = EVP_PKEY2PKCS8(ossl_pkey)))
+       {
+               fprintf(stderr, "ERROR: Could not convert EVP_PKEY to PKCS#8.\n");
+               EVP_PKEY_free(ossl_pkey);
+               return 1;
+       }
+       EVP_PKEY_free(ossl_pkey);
+
+       // Open output file
+       if (!(out = BIO_new_file (out_path, "wb")))
+       {
+               fprintf(stderr, "ERROR: Could not open the output file.\n");
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return 1;
+       }
+
+       // Write to disk
+       if (file_pin == NULL)
+       {
+               PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
+               printf("The key has been written to %s\n", out_path);
+       }
+       else
+       {
+               // Encrypt p8
+               if (!(p8 = PKCS8_encrypt(NID_pbeWithMD5AndDES_CBC, NULL,
+                                       file_pin, strlen(file_pin), NULL, 
+                                       0, PKCS12_DEFAULT_ITER, p8inf)))
+               {
+                       fprintf(stderr, "ERROR: Could not encrypt the PKCS#8 file\n");
+                       result = 1;
+               }
+               else
+               {
+                       PEM_write_bio_PKCS8(out, p8);
+                       X509_SIG_free(p8);
+                       printf("The key has been written to %s\n", out_path);
+               }
+       }
+
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       BIO_free_all(out);
+
+       return result;
+}
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1 b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1
new file mode 100644 (file)
index 0000000..b716bc8
--- /dev/null
@@ -0,0 +1,63 @@
+.TH SOFTHSM2-KEYCONV 1 "20 March 2014" "SoftHSM"
+.SH NAME
+softhsm2-keyconv \- converting from BIND to PKCS#8 key file format
+.SH SYNOPSIS
+.B softhsm2-keyconv
+.B \-\-in
+.I path
+.B \-\-out
+.I path
+.RB [ \-\-pin
+.IR PIN ]
+.SH DESCRIPTION
+.B softhsm2-keyconv
+can convert BIND .private-key files to the PKCS#8 file format.
+This is so that you can import the PKCS#8 file into
+libsofthsm using the command
+.BR softhsm2\-util .
+If you have another file format, then
+.B openssl
+probably can help you to convert it into the PKCS#8 file format.
+.SH OPTIONS
+.B \-\-help\fR, \fB\-h\fR
+Shows the help screen.
+.TP
+.B \-\-in \fIpath\fR
+The 
+.I path
+to the input file.
+.TP
+.B \-\-out \fIpath\fR
+The
+.I path
+to the output file.
+.TP
+.B \-\-pin \fIPIN\fR
+The
+.I PIN
+will be used to encrypt the PKCS#8 file.
+If not given then the PKCS#8 file will be unencrypted.
+.TP
+.B \-\-version\fR, \fB\-v\fR
+Show the version info.
+.SH EXAMPLES
+The following command can be used to convert a BIND .private-key file to a PKCS#8 file:
+.LP
+.RS
+.nf
+softhsm2-keyconv \-\-in Kexample.com.+007+05474.private \\
+.ti +0.7i
+\-\-out rsa.pem
+.fi
+.RE
+.LP
+.SH AUTHORS
+Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk.
+.SH "SEE ALSO"
+.IR softhsm2-migrate (1),
+.IR softhsm2-util (1),
+.IR softhsm2.conf (5),
+.IR openssl (1),
+.IR named (1),
+.IR dnssec-keygen (1),
+.IR dnssec-signzone (1)
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp
new file mode 100644 (file)
index 0000000..aeb75c3
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/************************************************************
+*
+* softhsm2-keyconv
+*
+* This program is for converting from BIND .private-key
+* format to PKCS#8 key file format. So that keys can be
+* imported from BIND to SoftHSM.
+*
+* Some of the design/code is from keyconv.c written by
+* Hakan Olsson and Jakob Schlyter in 2000 and 2001.
+*
+************************************************************/
+
+#include <config.h>
+#include "softhsm2-keyconv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define open _open
+#define close _close
+#endif
+#include <iostream>
+#include <fstream>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void usage()
+{
+       printf("Converting from BIND .private-key format to PKCS#8 key file format.\n");
+       printf("Usage: softhsm2-keyconv [OPTIONS]\n");
+       printf("Options:\n");
+       printf("  -h                  Shows this help screen.\n");
+       printf("  --help              Shows this help screen.\n");
+       printf("  --in <path>         The path to the input file.\n");
+       printf("  --out <path>        The path to the output file.\n");
+       printf("  --pin <PIN>         To encrypt PKCS#8 file. Optional.\n");
+       printf("  -v                  Show version info.\n");
+       printf("  --version           Show version info.\n");
+}
+
+// Give a number to each option
+enum {
+       OPT_HELP = 0x100,
+       OPT_IN,
+       OPT_OUT,
+       OPT_PIN,
+       OPT_VERSION
+};
+
+// Define the options
+static const struct option long_options[] = {
+       { "help",    0, NULL, OPT_HELP },
+       { "in",      1, NULL, OPT_IN },
+       { "out",     1, NULL, OPT_OUT },
+       { "pin",     1, NULL, OPT_PIN },
+       { "version", 0, NULL, OPT_VERSION },
+       { NULL,      0, NULL, 0 }
+};
+
+int main(int argc, char* argv[])
+{
+       int option_index = 0;
+       int opt, result;
+
+       char* in_path = NULL;
+       char* out_path = NULL;
+       char* file_pin = NULL;
+
+       if (argc == 1)
+       {
+               usage();
+               exit(0);
+       }
+
+       while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
+       {
+               switch (opt)
+               {
+                       case OPT_IN:
+                               in_path = optarg;
+                               break;
+                       case OPT_OUT:
+                               out_path = optarg;
+                               break;
+                       case OPT_PIN:
+                               file_pin = optarg;
+                               break;
+                       case OPT_VERSION:
+                       case 'v':
+                               printf("%s\n", PACKAGE_VERSION);
+                               exit(0);
+                               break;
+                       case OPT_HELP:
+                       case 'h':
+                       default:
+                               usage();
+                               exit(0);
+                               break;
+               }
+       }
+
+       // We should convert to PKCS#8
+       result = to_pkcs8(in_path, out_path, file_pin);
+
+       return result;
+}
+
+// Convert from BIND to PKCS#8
+int to_pkcs8(char* in_path, char* out_path, char* file_pin)
+{
+       FILE* file_pointer = NULL;
+       char line[MAX_LINE], data[MAX_LINE];
+       char* value_pointer = NULL;
+       int lineno = 0, m, n, error = 0, found, algorithm = DNS_KEYALG_ERROR, data_length;
+       uint32_t bitfield = 0;
+       key_material_t pkey[TAG_MAX];
+
+       if (in_path == NULL)
+       {
+               fprintf(stderr, "ERROR: A path to the input file must be supplied. Use --in <path>\n");
+               return 1;
+       }
+
+       if (out_path == NULL)
+       {
+               fprintf(stderr, "ERROR: A path to the output file must be supplied. Use --out <path>\n");
+               return 1;
+       }
+
+       file_pointer = fopen(in_path, "r");
+       if (file_pointer == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not open input file %.100s for reading.\n", in_path);
+               return 1;
+       }
+
+       // Loop over all of the lines
+       while (fgets(line, MAX_LINE, file_pointer) != NULL)
+       {
+               lineno++;
+
+               // Find the current text field in the BIND file.
+               for (m = 0, found = -1; found == -1 && file_tags[m]; m++)
+               {
+                       if (strncasecmp(line, file_tags[m], strlen(file_tags[m])) == 0)
+                       {
+                               found = m;
+                       }
+               }
+
+               // The text files is not recognized.
+               if (found == -1)
+               {
+                       fprintf(stderr, "ERROR: Unrecognized input line %i\n", lineno);
+                       fprintf(stderr, "ERROR: --> %s", line);
+                       continue;
+               }
+
+               // Point to the data for this text field.
+               value_pointer = line + strlen(file_tags[found]) + 1;
+
+               // Continue if we are at the end of the string
+               if (*value_pointer == 0)
+               {
+                       continue;
+               }
+
+               // Check that we do not get duplicates.
+               if (bitfield & (1 << found))
+               {
+                       fprintf(stderr, "ERROR: Duplicate \"%s\" field, line %i - ignored\n",
+                                       file_tags[found], lineno);
+                       continue;
+               }
+               bitfield |= (1 << found);
+
+               // Handle the data for this text field.
+               switch (found)
+               {
+                       case TAG_VERSION:
+                               if (sscanf(value_pointer, "v%i.%i", &m, &n) != 2)
+                               {
+                                       fprintf(stderr, "ERROR: Invalid/unknown version string "
+                                                       "(%.100s).\n", value_pointer);
+                                       error = 1;
+                                       break;
+                               }
+                               if (m > FILE_MAJOR_VERSION || (m == FILE_MAJOR_VERSION && n > FILE_MINOR_VERSION))
+                               {
+                                       fprintf(stderr, "ERROR: Cannot parse this version of file format, "
+                                                       "v%i.%i.\n", m, n);
+                                       error = 1;
+                               }
+                               break;
+                       case TAG_ALGORITHM:
+                               algorithm = strtol(value_pointer, NULL, 10);
+                               break;
+                       // RSA
+                       case TAG_MODULUS:
+                       case TAG_PUBEXP:
+                       case TAG_PRIVEXP:
+                       case TAG_PRIME1:
+                       case TAG_PRIME2:
+                       case TAG_EXP1:
+                       case TAG_EXP2:
+                       case TAG_COEFF:
+                       // DSA
+                       case TAG_PRIME:
+                       case TAG_SUBPRIME:
+                       case TAG_BASE:
+                       case TAG_PRIVVAL:
+                       case TAG_PUBVAL:
+                               data_length = b64_pton(value_pointer, (unsigned char*)data, MAX_LINE);
+                               if (data_length == -1)
+                               {
+                                       error = 1;
+                                       fprintf(stderr, "ERROR: Could not parse the base64 string on line %i.\n", lineno);
+                               }
+                               else
+                               {
+                                       pkey[found].big = malloc(data_length);
+                                       if (!pkey[found].big)
+                                       {
+                                               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+                                               error = 1;
+                                               break;
+                                       }
+                                       memcpy(pkey[found].big, data, data_length);
+                                       pkey[found].size = data_length;
+                               }
+                               break;
+                       // Do not need these
+                       case TAG_CREATED:
+                       case TAG_PUBLISH:
+                       case TAG_ACTIVATE:
+                       default:
+                               break;
+               }
+       }
+
+       fclose(file_pointer);
+
+       // Something went wrong. Clean up and quit.
+       if (error)
+       {
+               free_key_material(pkey);
+               return error;
+       }
+
+       // Create and set file permissions if the file does not exist.
+       int fd = open(out_path, O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd == -1)
+       {
+               fprintf(stderr, "ERROR: Could not open the output file: %s (errno %i)\n",
+                       out_path, errno);
+               free_key_material(pkey);
+               return 1;
+       }
+       ::close(fd);
+
+       crypto_init();
+
+       // Save the the key to the disk
+       switch (algorithm)
+       {
+               case DNS_KEYALG_ERROR:
+                       fprintf(stderr, "ERROR: The algorithm %i was not given in the file.\n",
+                                       algorithm);
+                       error = 1;
+                       break;
+               case DNS_KEYALG_RSAMD5:
+               case DNS_KEYALG_RSASHA1:
+               case DNS_KEYALG_RSASHA1_NSEC3_SHA1:
+               case DNS_KEYALG_RSASHA256:
+               case DNS_KEYALG_RSASHA512:
+                       error = save_rsa_pkcs8(out_path, file_pin, pkey);
+                       break;
+               case DNS_KEYALG_DSA:
+               case DNS_KEYALG_DSA_NSEC3_SHA1:
+                       error = save_dsa_pkcs8(out_path, file_pin, pkey);
+                       break;
+               case DNS_KEYALG_ECC:
+               case DNS_KEYALG_ECC_GOST:
+               default:
+                       fprintf(stderr, "ERROR: The algorithm %i is not supported.\n",
+                                       algorithm);
+                       error = 1;
+                       break;
+       }
+
+       crypto_final();
+       free_key_material(pkey);
+
+       return error;
+}
+
+// Free allocated memory
+void free_key_material(key_material_t* pkey)
+{
+       int i;
+
+       if (!pkey)
+       {
+               return;
+       }
+
+       for (i = 0; i < TAG_MAX; i++)
+       {
+               if (pkey[i].big)
+               {
+                       free(pkey[i].big);
+               }
+       }
+}
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h
new file mode 100644 (file)
index 0000000..fdeb719
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+#ifndef _SOFTHSM_V2_SOFTHSM2_KEYCONV_H
+#define _SOFTHSM_V2_SOFTHSM2_KEYCONV_H 1
+
+#include <stdlib.h>
+
+typedef struct key_material_t {
+       unsigned long size;
+       void* big;
+       key_material_t() {
+               size = 0;
+               big = NULL;
+       }
+} key_material_t;
+
+// Main functions
+
+void usage();
+int to_pkcs8(char* in_path, char* out_path, char* file_pin);
+
+// Support functions
+
+int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey);
+int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey);
+void free_key_material(key_material_t* pkey);
+void crypto_init();
+void crypto_final();
+
+// base64.c prototypes
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int b64_pton(const char* , unsigned char*, size_t);
+int b64_ntop(const unsigned char*, size_t, char*, size_t);
+#ifdef __cplusplus
+}
+#endif
+
+// The BIND file version number.
+#define FILE_MAJOR_VERSION     1
+#define FILE_MINOR_VERSION     3
+
+// Key algorithm number
+#define DNS_KEYALG_ERROR               -1
+#define DNS_KEYALG_RSAMD5              1
+#define DNS_KEYALG_DSA                 3
+#define DNS_KEYALG_ECC                 4
+#define DNS_KEYALG_RSASHA1             5
+#define DNS_KEYALG_DSA_NSEC3_SHA1      6
+#define DNS_KEYALG_RSASHA1_NSEC3_SHA1  7
+#define DNS_KEYALG_RSASHA256           8
+#define DNS_KEYALG_RSASHA512           10
+#define DNS_KEYALG_ECC_GOST            12
+
+// Maximum number of lines / line length
+#define MAX_LINE 4096
+
+// The text fields supported
+#if !defined(KEYCONV_BOTAN) && !defined(KEYCONV_OSSL)
+static const char* file_tags[] = {
+       "Private-key-format:",
+       "Algorithm:",
+       "Modulus:",
+       "PublicExponent:",
+       "PrivateExponent:",
+       "Prime1:",
+       "Prime2:",
+       "Exponent1:",
+       "Exponent2:",
+       "Coefficient:",
+       "Prime(p):",
+       "Private_value(x):",
+       "Public_value(y):",
+       "Subprime(q):",
+       "Base(g):",
+       "Created:",
+       "Publish:",
+       "Activate:",
+       NULL
+};
+#endif
+
+// The number of each text field.
+// Must match the tags above.
+enum FILE_TAGS {
+       TAG_VERSION = 0,
+       TAG_ALGORITHM,
+       TAG_MODULUS,
+       TAG_PUBEXP,
+       TAG_PRIVEXP,
+       TAG_PRIME1,
+       TAG_PRIME2,
+       TAG_EXP1,
+       TAG_EXP2,
+       TAG_COEFF,
+       TAG_PRIME,
+       TAG_PRIVVAL,
+       TAG_PUBVAL,
+       TAG_SUBPRIME,
+       TAG_BASE,
+       TAG_CREATED,
+       TAG_PUBLISH,
+       TAG_ACTIVATE,
+       // So we know how long this list is
+       TAG_MAX
+};
+
+#endif /* _SOFTHSM_V2_SOFTHSM2_KEYCONV_H */
diff --git a/SoftHSMv2/src/bin/migrate/Makefile.am b/SoftHSMv2/src/bin/migrate/Makefile.am
new file mode 100644 (file)
index 0000000..020c6a7
--- /dev/null
@@ -0,0 +1,20 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =          -I$(srcdir)/../../lib/pkcs11 \
+                       -I$(srcdir)/../common \
+                       @SQLITE3_INCLUDES@
+
+dist_man_MANS =                softhsm2-migrate.1
+
+bin_PROGRAMS =         softhsm2-migrate
+
+AUTOMAKE_OPTIONS =     subdir-objects
+
+softhsm2_migrate_SOURCES =     softhsm2-migrate.cpp \
+                               ../common/findslot.cpp \
+                               ../common/getpw.cpp \
+                               ../common/library.cpp
+softhsm2_migrate_LDADD =       @SQLITE3_LIBS@ \
+                               @YIELD_LIB@
+
+EXTRA_DIST =           $(srcdir)/*.h
diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.1 b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.1
new file mode 100644 (file)
index 0000000..65dc00c
--- /dev/null
@@ -0,0 +1,67 @@
+.TH SOFTHSM2-MIGRATE 1 "20 April 2016" "SoftHSM"
+.SH NAME
+softhsm2-migrate \- SoftHSM v1 migration tool
+.SH SYNOPSIS
+.PP
+.B softhsm2-migrate \-\-db
+.I path
+.B \-\-token
+.I label
+.RB [ \-\-pin
+.I PIN
+.B \-\-no\-public\-key]
+.SH DESCRIPTION
+.B softhsm2-migrate
+is a tool that can migrate SoftHSM v1 databases to PKCS#11.
+The default HSM is SoftHSM v2, but can be used with other 
+PKCS#11 libraries by using the option
+.B \-\-module
+.LP
+.SH OPTIONS
+.TP
+.B \-\-db \fIpath\fR
+The SoftHSM v1 database that is going to be migrated.
+The location of the token database can be found in
+the configuration file for SoftHSM v1.
+.TP
+.B \-\-help\fR, \fB\-h\fR
+Show the help information.
+.TP
+.B \-\-module \fIpath\fR
+Use another PKCS#11 library than SoftHSM.
+.TP
+.B \-\-no\-public\-key
+Do not migrate the public key.
+.TP
+.B \-\-pin \fIPIN\fR
+The
+.I PIN
+for the normal user.
+.TP
+.B \-\-serial \fInumber\fR
+Will use the token with a matching serial number.
+.TP
+.B \-\-slot \fInumber\fR
+The database will be migrated to this slot.
+.TP
+.B \-\-token \fIlabel\fR
+Will use the token with a matching token label.
+.TP
+.B \-\-version\fR, \fB\-v\fR
+Show the version info.
+.SH EXAMPLE
+.LP
+A token database can be migrated with the following command:
+.LP
+.RS
+.nf
+softhsm2-migrate \-\-db /home/user/token.db \-\-token mytoken
+.fi
+.RE
+.SH AUTHORS
+Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk.
+.LP
+.SH "SEE ALSO"
+.IR softhsm2-keyconv (1),
+.IR softhsm2-util (1),
+.IR softhsm2.conf (5)
diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp
new file mode 100644 (file)
index 0000000..0e6dc90
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-migrate.cpp
+
+ This program can be used for migrating SoftHSM v1 databases to any
+ PKCS#11 library. The default library is the libsofthsm2.so
+ *****************************************************************************/
+
+#include <config.h>
+#include "softhsm2-migrate.h"
+#include "findslot.h"
+#include "getpw.h"
+#include "library.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <iostream>
+#include <fstream>
+#include <sched.h>
+
+#ifdef _WIN32
+#define sched_yield() SleepEx(0, 0)
+#endif
+
+// Display the usage
+void usage()
+{
+       printf("SoftHSM migration tool. From SoftHSM v1 database to PKCS#11.\n");
+       printf("Usage: softhsm2-migrate [OPTIONS]\n");
+       printf("Options:\n");
+       printf("  -h                Shows this help screen.\n");
+       printf("  --help            Shows this help screen.\n");
+       printf("  --db <path>       The SoftHSM v1 database that is going to be migrated.\n");
+       printf("  --module <path>   Use another PKCS#11 library than SoftHSM.\n");
+       printf("  --no-public-key   Do not migrate the public key.\n");
+       printf("  --pin <PIN>       The PIN for the normal user.\n");
+       printf("  --serial <number> Will use the token with a matching serial number.\n");
+       printf("  --slot <number>   The slot where the token is located.\n");
+       printf("  --token <label>   Will use the token with a matching token label.\n");
+       printf("  -v                Show version info.\n");
+       printf("  --version         Show version info.\n");
+}
+
+// Enumeration of the long options
+enum {
+       OPT_HELP = 0x100,
+       OPT_DB,
+       OPT_MODULE,
+       OPT_NO_PUBLIC_KEY,
+       OPT_PIN,
+       OPT_SERIAL,
+       OPT_SLOT,
+       OPT_TOKEN,
+       OPT_VERSION
+};
+
+// Text representation of the long options
+static const struct option long_options[] = {
+       { "help",            0, NULL, OPT_HELP },
+       { "db",              1, NULL, OPT_DB },
+       { "module",          1, NULL, OPT_MODULE },
+       { "no-public-key",   0, NULL, OPT_NO_PUBLIC_KEY },
+       { "pin",             1, NULL, OPT_PIN },
+       { "serial",          1, NULL, OPT_SERIAL },
+       { "slot",            1, NULL, OPT_SLOT },
+       { "token" ,          1, NULL, OPT_TOKEN },
+       { "version",         0, NULL, OPT_VERSION },
+       { NULL,              0, NULL, 0 }
+};
+
+CK_FUNCTION_LIST_PTR p11;
+
+// Prepared statements
+sqlite3_stmt* select_an_attribute_sql = NULL;
+sqlite3_stmt* select_object_ids_sql = NULL;
+sqlite3_stmt* count_object_id_sql = NULL;
+
+
+// The main function
+int main(int argc, char* argv[])
+{
+       int option_index = 0;
+       int opt;
+
+       char* dbPath = NULL;
+       char* userPIN = NULL;
+       char* module = NULL;
+       char* slot = NULL;
+       char* serial = NULL;
+       char* token = NULL;
+       char *errMsg = NULL;
+       int noPublicKey = 0;
+
+       int result = 0;
+       CK_RV rv;
+
+       moduleHandle = NULL;
+       p11 = NULL;
+       CK_SLOT_ID slotID = 0;
+
+       if (argc == 1)
+       {
+               usage();
+               exit(0);
+       }
+
+       while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
+       {
+               switch (opt)
+               {
+                       case OPT_DB:
+                               dbPath = optarg;
+                               break;
+                       case OPT_SLOT:
+                               slot = optarg;
+                               break;
+                       case OPT_SERIAL:
+                               serial = optarg;
+                               break;
+                       case OPT_TOKEN:
+                               token = optarg;
+                               break;
+                       case OPT_MODULE:
+                               module = optarg;
+                               break;
+                       case OPT_NO_PUBLIC_KEY:
+                               noPublicKey = 1;
+                               break;
+                       case OPT_PIN:
+                               userPIN = optarg;
+                               break;
+                       case OPT_VERSION:
+                       case 'v':
+                               printf("%s\n", PACKAGE_VERSION);
+                               exit(0);
+                               break;
+                       case OPT_HELP:
+                       case 'h':
+                       default:
+                               usage();
+                               exit(0);
+                               break;
+               }
+       }
+
+       // Get a pointer to the function list for PKCS#11 library
+       CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg);
+       if (pGetFunctionList == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg);
+               fprintf(stderr, "ERROR: Please check log files for additional information.\n");
+               exit(1);
+       }
+
+       // Load the function list
+       (*pGetFunctionList)(&p11);
+
+       // Initialize the library
+       rv = p11->C_Initialize(NULL_PTR);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB);
+               fprintf(stderr, "ERROR: Please check log files for additional information.\n");
+               exit(1);
+       }
+
+       // Get the slotID
+       result = findSlot(slot, serial, token, slotID);
+
+       if (!result)
+       {
+               // Migrate the database
+               result = migrate(dbPath, slotID, userPIN, noPublicKey);
+       }
+
+       // Finalize the library
+       p11->C_Finalize(NULL_PTR);
+       unloadLibrary(moduleHandle);
+
+       return result;
+}
+
+// Migrate the database
+int migrate(char* dbPath, CK_SLOT_ID slotID, char* userPIN, int noPublicKey)
+{
+       CK_SESSION_HANDLE hSession;
+       sqlite3* db = NULL;
+       int result;
+
+       if (dbPath == NULL)
+       {
+               fprintf(stderr, "ERROR: A path to the database must be supplied. "
+                               "Use --db <path>\n");
+               return 1;
+       }
+
+       // Open the database
+       db = openDB(dbPath);
+       if (db == NULL)
+       {
+               return 1;
+       }
+
+       // Connect to the PKCS#11 library
+       result = openP11(slotID, userPIN, &hSession);
+       if (result)
+       {
+               sqlite3_close(db);
+               return result;
+       }
+
+       // Prepare the statements
+       if (prepStatements(db))
+       {
+               fprintf(stderr, "ERROR: Could not prepare the statements\n");
+               finalStatements();
+               sqlite3_close(db);
+               return 1;
+       }
+
+       // Start the migration
+       result = db2session(db, hSession, noPublicKey);
+
+       // Finalize the statements
+       finalStatements();
+
+       sqlite3_close(db);
+
+       if (result)
+       {
+               fprintf(stderr, "ERROR: Unable to migrate all of the objects.\n");
+       }
+       else
+       {
+               printf("The database has been migrated to the new HSM\n");
+       }
+
+       return result;
+}
+
+// Prepare the statements
+int prepStatements(sqlite3* db)
+{
+       select_an_attribute_sql = NULL;
+       select_object_ids_sql = NULL;
+       count_object_id_sql = NULL;
+
+       const char select_an_attribute_str[] =  "SELECT value,length FROM Attributes WHERE objectID = ? AND type = ?;";
+       const char select_object_ids_str[] =    "SELECT objectID FROM Objects;";
+       const char count_object_id_str[] =      "SELECT COUNT(objectID) FROM Objects;";
+
+       if
+       (
+               sqlite3_prepare_v2(db, select_an_attribute_str, -1, &select_an_attribute_sql, NULL) ||
+               sqlite3_prepare_v2(db, select_object_ids_str, -1, &select_object_ids_sql, NULL) ||
+               sqlite3_prepare_v2(db, count_object_id_str, -1, &count_object_id_sql, NULL)
+       )
+       {
+               return 1;
+       }
+
+       return 0;
+}
+
+// Finalize the statements
+void finalStatements()
+{
+       if (select_an_attribute_sql) sqlite3_finalize(select_an_attribute_sql);
+       if (select_object_ids_sql) sqlite3_finalize(select_object_ids_sql);
+       if (count_object_id_sql) sqlite3_finalize(count_object_id_sql);
+}
+
+// Open a connection to a valid SoftHSM v1 database
+sqlite3* openDB(char* dbPath)
+{
+       int result;
+       sqlite3* db = NULL;
+       sqlite3_stmt* pragStatem = NULL;
+       int dbVersion;
+
+       // Open the database
+       result = sqlite3_open(dbPath, &db);
+       if (result)
+       {
+               fprintf(stderr, "ERROR: Could not open token database. "
+                               "Probably wrong path or privileges: %s\n", dbPath);
+               return NULL;
+       }
+
+       // Check the schema version
+       if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &pragStatem, NULL))
+       {
+               fprintf(stderr, "ERROR: Could not prepare a SQL statement\n");
+               sqlite3_close(db);
+               return NULL;
+       }
+       if (sqlite3_step(pragStatem) == SQLITE_ROW)
+       {
+               dbVersion = sqlite3_column_int(pragStatem, 0);
+               sqlite3_finalize(pragStatem);
+
+               if (dbVersion != 100)
+               {
+                       fprintf(stderr, "ERROR: Wrong database schema version: %s\n", dbPath);
+                       sqlite3_close(db);
+                       return NULL;
+               }
+       }
+       else
+       {
+               fprintf(stderr, "ERROR: The token database has not been initialized by SoftHSM\n");
+               sqlite3_finalize(pragStatem);
+               sqlite3_close(db);
+               return NULL;
+       }
+
+       // Check that the Token table exist
+       result = sqlite3_exec(db, "SELECT COUNT(variableID) FROM Token;", NULL, NULL, NULL);
+       if (result)
+       {
+               fprintf(stderr, "ERROR: The Token table is missing the in database\n");
+               sqlite3_close(db);
+               return NULL;
+       }
+
+       // Check that the Objects table exist
+       result = sqlite3_exec(db, "SELECT COUNT(objectID) FROM Objects;", NULL, NULL, NULL);
+       if (result)
+       {
+               fprintf(stderr, "ERROR: The Objects table is missing the in database\n");
+               sqlite3_close(db);
+               return NULL;
+       }
+
+       // Check that the Attributes table exist
+       result = sqlite3_exec(db, "SELECT COUNT(attributeID) FROM Attributes;", NULL, NULL, NULL);
+       if (result)
+       {
+               fprintf(stderr, "ERROR: The Attributes table is missing in the database\n");
+               sqlite3_close(db);
+               return NULL;
+       }
+
+       return db;
+}
+
+// Connect and login to the token
+int openP11(CK_SLOT_ID slotID, char* userPIN, CK_SESSION_HANDLE* hSession)
+{
+       char user_pin_copy[MAX_PIN_LEN+1];
+       CK_RV rv;
+
+       rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
+                                       NULL_PTR, NULL_PTR, hSession);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_SLOT_ID_INVALID)
+               {
+                       fprintf(stderr, "ERROR: The given slot does not exist.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
+               }
+               return 1;
+       }
+
+       // Get the password
+       if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
+       {
+               fprintf(stderr, "ERROR: Could not get user PIN\n");
+               return 1;
+       }
+
+       rv = p11->C_Login(*hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_PIN_INCORRECT) {
+                       fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not log in on the token.\n");
+               }
+               return 1;
+       }
+
+       return 0;
+}
+
+// Migrate the database to the session
+int db2session(sqlite3* db, CK_SESSION_HANDLE hSession, int noPublicKey)
+{
+       CK_ULONG objectCount;
+       int result = 0, rv;
+       CK_OBJECT_HANDLE* objects = NULL;
+       CK_OBJECT_CLASS ckClass;
+
+       // Get all objects
+       objects = getObjects(db, &objectCount);
+       if (objects == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not find any objects in the database.\n");
+               return 1;
+       }
+
+       // Loop over all objects
+       for (unsigned i = 0; i < objectCount; i++)
+       {
+               ckClass = getObjectClass(objects[i]);
+
+               switch (ckClass)
+               {
+                       case CKO_PUBLIC_KEY:
+                               if (noPublicKey) continue;
+                               if (getKeyType(objects[i]) != CKK_RSA)
+                               {
+                                       fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. "
+                                               "Continuing.\n", objects[i]);
+                                       result = 1;
+                                       break;
+                               }
+                               rv = dbRSAPub2session(db, objects[i], hSession);
+                               if (rv) result = 1;
+                               break;
+                       case CKO_PRIVATE_KEY:
+                               if (getKeyType(objects[i]) != CKK_RSA)
+                               {
+                                       fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. "
+                                               "Continuing.\n", objects[i]);
+                                       result = 1;
+                                       break;
+                               }
+                               rv = dbRSAPriv2session(db, objects[i], hSession);
+                               if (rv) result = 1;
+                               break;
+                       case CKO_VENDOR_DEFINED:
+                               fprintf(stderr, "ERROR: Could not get the class of object %lu. "
+                                               "Continuing.\n", objects[i]);
+                               result = 1;
+                               break;
+                       default:
+                               fprintf(stderr, "ERROR: Not supporting class %lu in object %lu. "
+                                               "Continuing.\n", ckClass, objects[i]);
+                               result = 1;
+                               break;
+               }
+       }
+
+       free(objects);
+
+       return result;
+}
+
+// Get the key type from key objects
+CK_KEY_TYPE getKeyType(CK_OBJECT_HANDLE objectRef)
+{
+       int retSQL = 0;
+       CK_KEY_TYPE retVal = CKK_VENDOR_DEFINED;
+
+       sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+       sqlite3_bind_int(select_an_attribute_sql, 2, CKA_KEY_TYPE);
+
+       // Get result
+       while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+
+       // Get attribute
+       if (retSQL == SQLITE_ROW)
+       {
+               CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+               CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+               if (pValue != NULL_PTR && length == sizeof(CK_KEY_TYPE))
+               {
+                       retVal = *(CK_KEY_TYPE*)pValue;
+               }
+       }
+
+       sqlite3_reset(select_an_attribute_sql);
+
+       return retVal;
+}
+
+// Get the class of the object
+CK_OBJECT_CLASS getObjectClass(CK_OBJECT_HANDLE objectRef)
+{
+       int retSQL = 0;
+       CK_OBJECT_CLASS retVal = CKO_VENDOR_DEFINED;
+
+       sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+       sqlite3_bind_int(select_an_attribute_sql, 2, CKA_CLASS);
+
+       // Get the result
+       while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+
+       // Get attribute
+       if (retSQL == SQLITE_ROW)
+       {
+               CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+               CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+               if (pValue != NULL_PTR && length == sizeof(CK_OBJECT_CLASS))
+               {
+                       retVal = *(CK_OBJECT_CLASS*)pValue;
+               }
+       }
+
+       sqlite3_reset(select_an_attribute_sql);
+
+       return retVal;
+}
+
+// Get all object IDs
+CK_OBJECT_HANDLE* getObjects(sqlite3* /*db*/, CK_ULONG* objectCount)
+{
+       CK_ULONG objectsInDB;
+       CK_ULONG counter = 0;
+       CK_OBJECT_HANDLE* objectRefs = NULL;
+       int retSQL = 0;
+
+       *objectCount = 0;
+
+       // Find out how many objects we have.
+       while ((retSQL = sqlite3_step(count_object_id_sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+
+       if (retSQL != SQLITE_ROW)
+       {
+               fprintf(stderr, "ERROR: Could not count the number of objects in the database\n");
+               sqlite3_reset(count_object_id_sql);
+               return NULL;
+       }
+
+       // Get the number of objects
+       objectsInDB = sqlite3_column_int(count_object_id_sql, 0);
+       sqlite3_reset(count_object_id_sql);
+
+       if (!objectsInDB)
+       {
+               fprintf(stderr, "ERROR: There are not objects in the database\n");
+               return NULL;
+       }
+
+       // Create the object-reference buffer
+       objectRefs = (CK_OBJECT_HANDLE*)malloc(objectsInDB * sizeof(CK_OBJECT_HANDLE));
+       if (objectRefs == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory\n");
+               return NULL;
+       }
+
+       // Get all the object ids
+       while
+       (
+               ((retSQL = sqlite3_step(select_object_ids_sql)) == SQLITE_BUSY || retSQL == SQLITE_ROW) &&
+               counter < objectsInDB
+       )
+       {
+               if(retSQL == SQLITE_BUSY)
+               {
+                       sched_yield();
+                       continue;
+               }
+
+               objectRefs[counter++] = sqlite3_column_int(select_object_ids_sql, 0);
+       }
+
+       *objectCount = counter;
+
+       sqlite3_reset(select_object_ids_sql);
+
+       return objectRefs;
+}
+
+// Extract the information about the public RSA key and save it in the token
+int dbRSAPub2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession)
+{
+       int result = 0;
+       int i;
+       CK_OBJECT_HANDLE hKey;
+       CK_RV rv;
+
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,            NULL,   0 },
+               { CKA_KEY_TYPE,         NULL,   0 },
+               { CKA_TOKEN,            NULL,   0 },
+               { CKA_PRIVATE,          NULL,   0 },
+               { CKA_MODIFIABLE,       NULL,   0 },
+               { CKA_LABEL,            NULL,   0 },
+               { CKA_ID,               NULL,   0 },
+               { CKA_START_DATE,       NULL,   0 },
+               { CKA_END_DATE,         NULL,   0 },
+               { CKA_DERIVE,           NULL,   0 },
+               { CKA_SUBJECT,          NULL,   0 },
+               { CKA_ENCRYPT,          NULL,   0 },
+               { CKA_VERIFY,           NULL,   0 },
+               { CKA_VERIFY_RECOVER,   NULL,   0 },
+               { CKA_WRAP,             NULL,   0 },
+               { CKA_MODULUS,          NULL,   0 },
+               { CKA_PUBLIC_EXPONENT,  NULL,   0 }
+       };
+
+       for (i = 0; i < 17; i++)
+       {
+               result = getAttribute(objectID, &pubTemplate[i]);
+               if (result)
+               {
+                       freeTemplate(pubTemplate, 17);
+                       return 1;
+               }
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 17, &hKey);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR %X: Could not save the public key in the token. "
+                               "Skipping object %lu\n", (unsigned int)rv, objectID);
+               result = 1;
+       }
+       else
+       {
+               printf("Object %lu has been migrated\n", objectID);
+       }
+
+       freeTemplate(pubTemplate, 17);
+
+       return result;
+}
+
+// Extract the information about the private RSA key and save it in the token
+int dbRSAPriv2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession)
+{
+       int result = 0;
+       int i;
+       CK_OBJECT_HANDLE hKey;
+       CK_RV rv;
+
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,                    NULL,   0 },
+               { CKA_TOKEN,                    NULL,   0 },
+               { CKA_PRIVATE,                  NULL,   0 },
+               { CKA_MODIFIABLE,               NULL,   0 },
+               { CKA_LABEL,                    NULL,   0 },
+               { CKA_KEY_TYPE,                 NULL,   0 },
+               { CKA_ID,                       NULL,   0 },
+               { CKA_START_DATE,               NULL,   0 },
+               { CKA_END_DATE,                 NULL,   0 },
+               { CKA_DERIVE,                   NULL,   0 },
+               { CKA_SUBJECT,                  NULL,   0 },
+               { CKA_SENSITIVE,                NULL,   0 },
+               { CKA_DECRYPT,                  NULL,   0 },
+               { CKA_SIGN,                     NULL,   0 },
+               { CKA_SIGN_RECOVER,             NULL,   0 },
+               { CKA_UNWRAP,                   NULL,   0 },
+               { CKA_EXTRACTABLE,              NULL,   0 },
+               { CKA_WRAP_WITH_TRUSTED,        NULL,   0 },
+               { CKA_MODULUS,                  NULL,   0 },
+               { CKA_PUBLIC_EXPONENT,          NULL,   0 },
+               { CKA_PRIVATE_EXPONENT,         NULL,   0 },
+               { CKA_PRIME_1,                  NULL,   0 },
+               { CKA_PRIME_2,                  NULL,   0 }
+// SoftHSM v1 did not store these values
+//             { CKA_EXPONENT_1,               NULL,   0 },
+//             { CKA_EXPONENT_2,               NULL,   0 },
+//             { CKA_COEFFICIENT,              NULL,   0 }
+       };
+
+       for (i = 0; i < 23; i++)
+       {
+               result = getAttribute(objectID, &privTemplate[i]);
+               if (result)
+               {
+                       freeTemplate(privTemplate, 23);
+                       return 1;
+               }
+       }
+
+       rv = p11->C_CreateObject(hSession, privTemplate, 23, &hKey);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR %X: Could not save the private key in the token. "
+                               "Skipping object %lu\n", (unsigned int)rv, objectID);
+               result = 1;
+       }
+       else
+       {
+               printf("Object %lu has been migrated\n", objectID);
+       }
+
+       freeTemplate(privTemplate, 23);
+
+       return result;
+}
+
+// Get the value of the given attribute
+int getAttribute(CK_OBJECT_HANDLE objectRef, CK_ATTRIBUTE* attTemplate)
+{
+       int retSQL = 0;
+       int retVal = 0;
+
+       sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+       sqlite3_bind_int(select_an_attribute_sql, 2, attTemplate->type);
+
+       // Get result
+       while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+       {
+               sched_yield();
+       }
+
+       // Get the attribute
+       if (retSQL == SQLITE_ROW)
+       {
+               CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+               CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+               if (length)
+               {
+                       attTemplate->pValue = malloc(length);
+                       if (!attTemplate->pValue)
+                       {
+                               fprintf(stderr, "ERROR: Could not allocate memory. "
+                                               "Skipping object %lu\n", objectRef);
+                               retVal = 1;
+                       }
+                       else
+                       {
+                               // Copy data
+                               memcpy(attTemplate->pValue, pValue, length);
+                       }
+               }
+
+               attTemplate->ulValueLen = length;
+       }
+       else
+       {
+               fprintf(stderr, "ERROR: Do not have attribute %lu. "
+                               "Skipping object %lu\n", attTemplate->type, objectRef);
+               retVal = 1;
+       }
+
+       sqlite3_reset(select_an_attribute_sql);
+
+       return retVal;
+}
+
+// Free allocated memory in the template
+void freeTemplate(CK_ATTRIBUTE* attTemplate, int size)
+{
+       int i;
+
+       if (!attTemplate) return;
+
+       for (i = 0; i < size; i++)
+       {
+               if(attTemplate[i].pValue)
+               {
+                       free(attTemplate[i].pValue);
+               }
+       }
+}
diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.h b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.h
new file mode 100644 (file)
index 0000000..1b5a066
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-migrate.h
+
+ This program can be used for migrating SoftHSM v1 databases to any
+ PKCS#11 library. The default library is the libsofthsm2.so
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SOFTHSM2_MIGRATE_H
+#define _SOFTHSM_V2_SOFTHSM2_MIGRATE_H
+
+#include "cryptoki.h"
+#include <sqlite3.h>
+
+// Main functions
+
+void usage();
+int migrate(char* dbPath, CK_SLOT_ID slotID, char* userPIN, int noPublicKey);
+
+// Support functions
+
+sqlite3* openDB(char* dbPath);
+int openP11(CK_SLOT_ID slotID, char* userPIN, CK_SESSION_HANDLE* hSession);
+int db2session(sqlite3* db, CK_SESSION_HANDLE hSession, int noPublicKey);
+int dbRSAPub2session(sqlite3* db, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession);
+int dbRSAPriv2session(sqlite3* db, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession);
+void freeTemplate(CK_ATTRIBUTE* attTemplate, int size);
+
+// Database functions
+
+CK_OBJECT_HANDLE* getObjects(sqlite3* db, CK_ULONG* objectCount);
+CK_OBJECT_CLASS getObjectClass(CK_OBJECT_HANDLE objectRef);
+CK_KEY_TYPE getKeyType(CK_OBJECT_HANDLE objectRef);
+int getAttribute(CK_OBJECT_HANDLE objectRef, CK_ATTRIBUTE* attTemplate);
+int prepStatements(sqlite3* db);
+void finalStatements();
+
+// Library
+
+static void* moduleHandle;
+extern CK_FUNCTION_LIST_PTR p11;
+
+#endif // !_SOFTHSM_V2_SOFTHSM2_MIGRATE_H
diff --git a/SoftHSMv2/src/bin/util/Makefile.am b/SoftHSMv2/src/bin/util/Makefile.am
new file mode 100644 (file)
index 0000000..a552e14
--- /dev/null
@@ -0,0 +1,40 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =          -I$(srcdir)/../common \
+                       -I$(srcdir)/../../lib/ \
+                       -I$(srcdir)/../../lib/common \
+                       -I$(srcdir)/../../lib/crypto \
+                       -I$(srcdir)/../../lib/data_mgr \
+                       -I$(srcdir)/../../lib/object_store \
+                       -I$(srcdir)/../../lib/pkcs11 \
+                       @CRYPTO_INCLUDES@ \
+                       @SQLITE3_INCLUDES@
+
+dist_man_MANS =                softhsm2-util.1
+
+bin_PROGRAMS =         softhsm2-util
+
+AUTOMAKE_OPTIONS =     subdir-objects
+
+softhsm2_util_SOURCES =        softhsm2-util.cpp \
+                       ../common/findslot.cpp \
+                       ../common/getpw.cpp \
+                       ../common/library.cpp
+
+softhsm2_util_LDADD =  @CRYPTO_LIBS@ \
+                       @SQLITE3_LIBS@ \
+                       ../../lib/libsofthsm_convarch.la
+
+# Compile with support of OpenSSL
+if WITH_OPENSSL
+softhsm2_util_SOURCES +=       softhsm2-util-ossl.cpp \
+                               ../../lib/crypto/OSSLComp.cpp
+endif
+
+# Compile with support of Botan
+if WITH_BOTAN
+softhsm2_util_SOURCES +=       softhsm2-util-botan.cpp
+endif
+
+EXTRA_DIST =           $(srcdir)/*.h \
+                       $(srcdir)/*.cpp
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp
new file mode 100644 (file)
index 0000000..cecc0ce
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util-botan.cpp
+
+ Code specific for Botan
+ *****************************************************************************/
+
+#include <config.h>
+#define UTIL_BOTAN
+#include "softhsm2-util.h"
+#include "softhsm2-util-botan.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+#include <botan/init.h>
+#include <botan/auto_rng.h>
+#include <botan/pkcs8.h>
+#include <botan/bigint.h>
+#include <botan/version.h>
+#include <botan/der_enc.h>
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+#include <botan/libstate.h>
+bool wasInitialized = false;
+#endif
+
+// Init Botan
+void crypto_init()
+{
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       // The PKCS#11 library might be using Botan
+       // Check if it has already initialized Botan
+       if (Botan::Global_State_Management::global_state_exists())
+       {
+               wasInitialized = true;
+       }
+
+       if (!wasInitialized)
+       {
+               Botan::LibraryInitializer::initialize("thread_safe=true");
+       }
+#else
+       Botan::LibraryInitializer::initialize("thread_safe=true");
+#endif
+}
+
+// Final Botan
+void crypto_final()
+{
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       if (!wasInitialized)
+       {
+               Botan::LibraryInitializer::deinitialize();
+       }
+#else
+       Botan::LibraryInitializer::deinitialize();
+#endif
+}
+
+// Import a aes secret key from given path
+int crypto_import_aes_key
+(
+       CK_SESSION_HANDLE hSession,
+       char* filePath,
+       char* label,
+       char* objID,
+       size_t objIDLen
+)
+{
+       const size_t cMaxAesKeySize = 1024 + 1; // including null-character
+       char aesKeyValue[cMaxAesKeySize];
+       FILE* fp = fopen(filePath, "rb");
+       if (fp == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not open the secret key file.\n");
+               return 1;
+       }
+       if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not read the secret key file.\n");
+               fclose(fp);
+               return 1;
+       }
+       fclose(fp);
+
+       CK_BBOOL ckTrue = CK_TRUE;
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_AES;
+       CK_ATTRIBUTE keyTemplate[] = {
+               { CKA_CLASS,            &keyClass,    sizeof(keyClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_SENSITIVE,        &ckTrue,      sizeof(ckTrue) },
+               { CKA_VALUE,            &aesKeyValue, strlen(aesKeyValue) }
+       };
+
+       CK_OBJECT_HANDLE hKey;
+       CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the secret key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+// Import a key pair from given path
+int crypto_import_key_pair
+(
+       CK_SESSION_HANDLE hSession,
+       char* filePath,
+       char* filePIN,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey
+)
+{
+       Botan::Private_Key* pkey = crypto_read_file(filePath, filePIN);
+       if (pkey == NULL)
+       {
+               return 1;
+       }
+
+       Botan::RSA_PrivateKey* rsa = NULL;
+       Botan::DSA_PrivateKey* dsa = NULL;
+#ifdef WITH_ECC
+       Botan::ECDSA_PrivateKey* ecdsa = NULL;
+#endif
+
+       if (pkey->algo_name().compare("RSA") == 0)
+       {
+               rsa = dynamic_cast<Botan::RSA_PrivateKey*>(pkey);
+       }
+       else if (pkey->algo_name().compare("DSA") == 0)
+       {
+               dsa = dynamic_cast<Botan::DSA_PrivateKey*>(pkey);
+       }
+#ifdef WITH_ECC
+       else if (pkey->algo_name().compare("ECDSA") == 0)
+       {
+               ecdsa = dynamic_cast<Botan::ECDSA_PrivateKey*>(pkey);
+       }
+#endif
+       else
+       {
+               fprintf(stderr, "ERROR: %s is not a supported algorithm.\n",
+                               pkey->algo_name().c_str());
+               delete pkey;
+               return 1;
+       }
+
+       int result = 0;
+
+       if (rsa)
+       {
+               result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa);
+       }
+       else if (dsa)
+       {
+               result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa);
+       }
+#ifdef WITH_ECC
+       else if (ecdsa)
+       {
+               result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa);
+       }
+#endif
+       else
+       {
+               fprintf(stderr, "ERROR: Could not get the key material.\n");
+               result = 1;
+       }
+
+       delete pkey;
+       return result;
+}
+
+// Read the key from file
+Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN)
+{
+       if (filePath == NULL)
+       {
+               return NULL;
+       }
+
+       Botan::AutoSeeded_RNG* rng = new Botan::AutoSeeded_RNG();
+       Botan::Private_Key* pkey = NULL;
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               if (filePIN == NULL)
+               {
+                       pkey = Botan::PKCS8::load_key(std::string(filePath), *rng);
+               }
+               else
+               {
+                       pkey = Botan::PKCS8::load_key(std::string(filePath), *rng, std::string(filePIN));
+               }
+#else
+               if (filePIN == NULL)
+               {
+                       pkey = Botan::PKCS8::load_key(filePath, *rng);
+               }
+               else
+               {
+                       pkey = Botan::PKCS8::load_key(filePath, *rng, filePIN);
+               }
+#endif
+       }
+       catch (std::exception& e)
+       {
+               fprintf(stderr, "%s\n", e.what());
+               fprintf(stderr, "ERROR: Perhaps wrong path to file, wrong file format, "
+                               "or wrong PIN to file (--file-pin <PIN>).\n");
+               delete rng;
+               return NULL;
+       }
+       delete rng;
+
+       return pkey;
+}
+
+// Save the key data in PKCS#11
+int crypto_save_rsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       Botan::RSA_PrivateKey* rsa
+)
+{
+       rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa);
+       if (!keyMat)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_RSA;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,            &pubClass,    sizeof(pubClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckToken,     sizeof(ckToken) },
+               { CKA_VERIFY,           &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_WRAP,             &ckTrue,      sizeof(ckTrue) },
+               { CKA_PUBLIC_EXPONENT,  keyMat->bigE, keyMat->sizeE },
+               { CKA_MODULUS,          keyMat->bigN, keyMat->sizeN }
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,            &privClass,      sizeof(privClass) },
+               { CKA_KEY_TYPE,         &keyType,        sizeof(keyType) },
+               { CKA_LABEL,            label,           strlen(label) },
+               { CKA_ID,               objID,           objIDLen },
+               { CKA_SIGN,             &ckTrue,         sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckTrue,         sizeof(ckTrue) },
+               { CKA_UNWRAP,           &ckTrue,         sizeof(ckTrue) },
+               { CKA_SENSITIVE,        &ckTrue,         sizeof(ckTrue) },
+               { CKA_TOKEN,            &ckTrue,         sizeof(ckTrue) },
+               { CKA_PRIVATE,          &ckTrue,         sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,      &ckFalse,        sizeof(ckFalse) },
+               { CKA_PUBLIC_EXPONENT,  keyMat->bigE,    keyMat->sizeE },
+               { CKA_MODULUS,          keyMat->bigN,    keyMat->sizeN },
+               { CKA_PRIVATE_EXPONENT, keyMat->bigD,    keyMat->sizeD },
+               { CKA_PRIME_1,          keyMat->bigP,    keyMat->sizeP },
+               { CKA_PRIME_2,          keyMat->bigQ,    keyMat->sizeQ },
+               { CKA_EXPONENT_1,       keyMat->bigDMP1, keyMat->sizeDMP1 },
+               { CKA_EXPONENT_2,       keyMat->bigDMQ1, keyMat->sizeDMQ1 },
+               { CKA_COEFFICIENT,      keyMat->bigIQMP, keyMat->sizeIQMP }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_rsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2);
+       crypto_free_rsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the Botan key to binary
+rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa)
+{
+       if (rsa == NULL)
+       {
+               return NULL;
+       }
+
+       rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+       keyMat->sizeE = rsa->get_e().bytes();
+       keyMat->sizeN = rsa->get_n().bytes();
+       keyMat->sizeD = rsa->get_d().bytes();
+       keyMat->sizeP = rsa->get_p().bytes();
+       keyMat->sizeQ = rsa->get_q().bytes();
+       keyMat->sizeDMP1 = rsa->get_d1().bytes();
+       keyMat->sizeDMQ1 = rsa->get_d2().bytes();
+       keyMat->sizeIQMP = rsa->get_c().bytes();
+
+       keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE);
+       keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN);
+       keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD);
+       keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP);
+       keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+       keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1);
+       keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1);
+       keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP);
+
+       if
+       (
+               !keyMat->bigE ||
+               !keyMat->bigN ||
+               !keyMat->bigD ||
+               !keyMat->bigP ||
+               !keyMat->bigQ ||
+               !keyMat->bigDMP1 ||
+               !keyMat->bigDMQ1 ||
+               !keyMat->bigIQMP
+       )
+       {
+               crypto_free_rsa(keyMat);
+               return NULL;
+       }
+
+       rsa->get_e().binary_encode((Botan::byte*)keyMat->bigE);
+       rsa->get_n().binary_encode((Botan::byte*)keyMat->bigN);
+       rsa->get_d().binary_encode((Botan::byte*)keyMat->bigD);
+       rsa->get_p().binary_encode((Botan::byte*)keyMat->bigP);
+       rsa->get_q().binary_encode((Botan::byte*)keyMat->bigQ);
+       rsa->get_d1().binary_encode((Botan::byte*)keyMat->bigDMP1);
+       rsa->get_d2().binary_encode((Botan::byte*)keyMat->bigDMQ1);
+       rsa->get_c().binary_encode((Botan::byte*)keyMat->bigIQMP);
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_rsa(rsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->bigE) free(keyMat->bigE);
+       if (keyMat->bigN) free(keyMat->bigN);
+       if (keyMat->bigD) free(keyMat->bigD);
+       if (keyMat->bigP) free(keyMat->bigP);
+       if (keyMat->bigQ) free(keyMat->bigQ);
+       if (keyMat->bigDMP1) free(keyMat->bigDMP1);
+       if (keyMat->bigDMQ1) free(keyMat->bigDMQ1);
+       if (keyMat->bigIQMP) free(keyMat->bigIQMP);
+       free(keyMat);
+}
+
+// Save the key data in PKCS#11
+int crypto_save_dsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       Botan::DSA_PrivateKey* dsa
+)
+{
+       dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa);
+       if (keyMat == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_DSA;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,            &pubClass,    sizeof(pubClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckToken,     sizeof(ckToken) },
+               { CKA_VERIFY,           &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckFalse,     sizeof(ckFalse) },
+               { CKA_WRAP,             &ckFalse,     sizeof(ckFalse) },
+               { CKA_PRIME,            keyMat->bigP, keyMat->sizeP },
+               { CKA_SUBPRIME,         keyMat->bigQ, keyMat->sizeQ },
+               { CKA_BASE,             keyMat->bigG, keyMat->sizeG },
+               { CKA_VALUE,            keyMat->bigY, keyMat->sizeY }
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,            &privClass,   sizeof(privClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_SIGN,             &ckTrue,      sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckFalse,     sizeof(ckFalse) },
+               { CKA_UNWRAP,           &ckFalse,     sizeof(ckFalse) },
+               { CKA_SENSITIVE,        &ckTrue,      sizeof(ckTrue) },
+               { CKA_TOKEN,            &ckTrue,      sizeof(ckTrue) },
+               { CKA_PRIVATE,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,      &ckFalse,     sizeof(ckFalse) },
+               { CKA_PRIME,            keyMat->bigP, keyMat->sizeP },
+               { CKA_SUBPRIME,         keyMat->bigQ, keyMat->sizeQ },
+               { CKA_BASE,             keyMat->bigG, keyMat->sizeG },
+               { CKA_VALUE,            keyMat->bigX, keyMat->sizeX }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_dsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2);
+       crypto_free_dsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the Botan key to binary
+dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa)
+{
+       if (dsa == NULL)
+       {
+               return NULL;
+       }
+
+       dsa_key_material_t *keyMat = (dsa_key_material_t *)malloc(sizeof(dsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+       keyMat->sizeP = dsa->group_p().bytes();
+       keyMat->sizeQ = dsa->group_q().bytes();
+       keyMat->sizeG = dsa->group_g().bytes();
+       keyMat->sizeX = dsa->get_x().bytes();
+       keyMat->sizeY = dsa->get_y().bytes();
+
+       keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP);
+       keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+       keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG);
+       keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX);
+       keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY);
+
+       if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY)
+       {
+               crypto_free_dsa(keyMat);
+               return NULL;
+       }
+
+       dsa->group_p().binary_encode((Botan::byte*)keyMat->bigP);
+       dsa->group_q().binary_encode((Botan::byte*)keyMat->bigQ);
+       dsa->group_g().binary_encode((Botan::byte*)keyMat->bigG);
+       dsa->get_x().binary_encode((Botan::byte*)keyMat->bigX);
+       dsa->get_y().binary_encode((Botan::byte*)keyMat->bigY);
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_dsa(dsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->bigP) free(keyMat->bigP);
+       if (keyMat->bigQ) free(keyMat->bigQ);
+       if (keyMat->bigG) free(keyMat->bigG);
+       if (keyMat->bigX) free(keyMat->bigX);
+       if (keyMat->bigY) free(keyMat->bigY);
+       free(keyMat);
+}
+
+#ifdef WITH_ECC
+// Save the key data in PKCS#11
+int crypto_save_ecdsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       Botan::ECDSA_PrivateKey* ecdsa
+)
+{
+       ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa);
+       if (keyMat == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_ECDSA;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,          &pubClass,         sizeof(pubClass) },
+               { CKA_KEY_TYPE,       &keyType,          sizeof(keyType) },
+               { CKA_LABEL,          label,             strlen(label) },
+               { CKA_ID,             objID,             objIDLen },
+               { CKA_TOKEN,          &ckToken,          sizeof(ckToken) },
+               { CKA_VERIFY,         &ckTrue,           sizeof(ckTrue) },
+               { CKA_ENCRYPT,        &ckFalse,          sizeof(ckFalse) },
+               { CKA_WRAP,           &ckFalse,          sizeof(ckFalse) },
+               { CKA_EC_PARAMS,      keyMat->derParams, keyMat->sizeParams },
+               { CKA_EC_POINT,       keyMat->derQ,      keyMat->sizeQ }
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,          &privClass,        sizeof(privClass) },
+               { CKA_KEY_TYPE,       &keyType,          sizeof(keyType) },
+               { CKA_LABEL,          label,             strlen(label) },
+               { CKA_ID,             objID,             objIDLen },
+               { CKA_SIGN,           &ckTrue,           sizeof(ckTrue) },
+               { CKA_DECRYPT,        &ckFalse,          sizeof(ckFalse) },
+               { CKA_UNWRAP,         &ckFalse,          sizeof(ckFalse) },
+               { CKA_SENSITIVE,      &ckTrue,           sizeof(ckTrue) },
+               { CKA_TOKEN,          &ckTrue,           sizeof(ckTrue) },
+               { CKA_PRIVATE,        &ckTrue,           sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,    &ckFalse,          sizeof(ckFalse) },
+               { CKA_EC_PARAMS,      keyMat->derParams, keyMat->sizeParams },
+               { CKA_VALUE,          keyMat->bigD,      keyMat->sizeD }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_ecdsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2);
+       crypto_free_ecdsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the Botan key to binary
+ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa)
+{
+       if (ecdsa == NULL)
+       {
+               return NULL;
+       }
+
+       ecdsa_key_material_t *keyMat = (ecdsa_key_material_t *)malloc(sizeof(ecdsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       Botan::secure_vector<Botan::byte> derPoint;
+#else
+       Botan::SecureVector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       Botan::SecureVector<Botan::byte> derPoint;
+#endif
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(),
+                       Botan::PointGFp::UNCOMPRESSED);
+#else
+               Botan::SecureVector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(),
+                       Botan::PointGFp::UNCOMPRESSED);
+#endif
+
+               derPoint = Botan::DER_Encoder()
+                       .encode(repr, Botan::OCTET_STRING)
+                       .get_contents();
+        }
+       catch (...)
+       {
+               return NULL;
+       }
+
+       keyMat->sizeParams = derEC.size();
+       keyMat->sizeD = ecdsa->private_value().bytes();
+       keyMat->sizeQ = derPoint.size();
+
+       keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams);
+       keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD);
+       keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+
+       if (!keyMat->derParams || !keyMat->bigD || !keyMat->derQ)
+       {
+               crypto_free_ecdsa(keyMat);
+               return NULL;
+       }
+
+       memcpy(keyMat->derParams, &derEC[0], derEC.size());
+       ecdsa->private_value().binary_encode((Botan::byte*)keyMat->bigD);
+       memcpy(keyMat->derQ, &derPoint[0], derPoint.size());
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_ecdsa(ecdsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->derParams) free(keyMat->derParams);
+       if (keyMat->bigD) free(keyMat->bigD);
+       if (keyMat->derQ) free(keyMat->derQ);
+       free(keyMat);
+}
+#endif
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.h b/SoftHSMv2/src/bin/util/softhsm2-util-botan.h
new file mode 100644 (file)
index 0000000..8cd4a5e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util-botan.h
+
+ Header file for Botan implemented
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H
+#define _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H
+
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#ifdef WITH_ECC
+#include <botan/ecdsa.h>
+#endif
+
+typedef struct rsa_key_material_t {
+       CK_ULONG sizeE;
+       CK_ULONG sizeN;
+       CK_ULONG sizeD;
+       CK_ULONG sizeP;
+       CK_ULONG sizeQ;
+       CK_ULONG sizeDMP1;
+       CK_ULONG sizeDMQ1;
+       CK_ULONG sizeIQMP;
+       CK_VOID_PTR bigE;
+       CK_VOID_PTR bigN;
+       CK_VOID_PTR bigD;
+       CK_VOID_PTR bigP;
+       CK_VOID_PTR bigQ;
+       CK_VOID_PTR bigDMP1;
+       CK_VOID_PTR bigDMQ1;
+       CK_VOID_PTR bigIQMP;
+       rsa_key_material_t() {
+               sizeE = 0;
+               sizeN = 0;
+               sizeD = 0;
+               sizeP = 0;
+               sizeQ = 0;
+               sizeDMP1 = 0;
+               sizeDMQ1 = 0;
+               sizeIQMP = 0;
+               bigE = NULL_PTR;
+               bigN = NULL_PTR;
+               bigD = NULL_PTR;
+               bigP = NULL_PTR;
+               bigQ = NULL_PTR;
+               bigDMP1 = NULL_PTR;
+               bigDMQ1 = NULL_PTR;
+               bigIQMP = NULL_PTR;
+       }
+} rsa_key_material_t;
+
+typedef struct dsa_key_material_t {
+       CK_ULONG sizeP;
+       CK_ULONG sizeQ;
+       CK_ULONG sizeG;
+       CK_ULONG sizeX;
+       CK_ULONG sizeY;
+       CK_VOID_PTR bigP;
+       CK_VOID_PTR bigQ;
+       CK_VOID_PTR bigG;
+       CK_VOID_PTR bigX;
+       CK_VOID_PTR bigY;
+       dsa_key_material_t() {
+               sizeP = 0;
+               sizeQ = 0;
+               sizeG = 0;
+               sizeX = 0;
+               sizeY = 0;
+               bigP = NULL_PTR;
+               bigQ = NULL_PTR;
+               bigG = NULL_PTR;
+               bigX = NULL_PTR;
+               bigY = NULL_PTR;
+       }
+} dsa_key_material_t;
+
+#ifdef WITH_ECC
+typedef struct ecdsa_key_material_t {
+       CK_ULONG sizeParams;
+       CK_ULONG sizeD;
+       CK_ULONG sizeQ;
+       CK_VOID_PTR derParams;
+       CK_VOID_PTR bigD;
+       CK_VOID_PTR derQ;
+       ecdsa_key_material_t() {
+               sizeParams = 0;
+               sizeD = 0;
+               sizeQ = 0;
+               derParams = NULL_PTR;
+               bigD = NULL_PTR;
+               derQ = NULL_PTR;
+       }
+} ecdsa_key_material_t;
+#endif
+
+Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN);
+
+// RSA
+int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::RSA_PrivateKey* rsa);
+rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa);
+void crypto_free_rsa(rsa_key_material_t* keyMat);
+
+// DSA
+int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::DSA_PrivateKey* dsa);
+dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa);
+void crypto_free_dsa(dsa_key_material_t* keyMat);
+
+// ECDSA
+#ifdef WITH_ECC
+int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::ECDSA_PrivateKey* ecdsa);
+ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa);
+void crypto_free_ecdsa(ecdsa_key_material_t* keyMat);
+#endif
+
+#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp
new file mode 100644 (file)
index 0000000..fedfd28
--- /dev/null
@@ -0,0 +1,790 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util-ossl.cpp
+
+ Code specific for OpenSSL
+ *****************************************************************************/
+
+#include <config.h>
+#define UTIL_OSSL
+#include "softhsm2-util.h"
+#include "softhsm2-util-ossl.h"
+#include "OSSLComp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+
+// Init OpenSSL
+void crypto_init()
+{
+       // We do not need to do this one
+       // OpenSSL_add_all_algorithms();
+#ifdef WITH_FIPS
+       // The PKCS#11 library might be using a FIPS capable OpenSSL
+       if (FIPS_mode())
+               return;
+       if (!FIPS_mode_set(1))
+       {
+               fprintf(stderr, "ERROR: can't enter into FIPS mode.\n");
+               exit(0);
+       }
+#endif
+}
+
+// Final OpenSSL
+void crypto_final()
+{
+       // EVP_cleanup();
+       CRYPTO_cleanup_all_ex_data();
+}
+
+int crypto_import_aes_key
+(
+       CK_SESSION_HANDLE hSession,
+       char* filePath,
+       char* label,
+       char* objID,
+       size_t objIDLen
+)
+{
+       const size_t cMaxAesKeySize = 1024 + 1; // including null-character
+       char aesKeyValue[cMaxAesKeySize];
+       FILE* fp = fopen(filePath, "rb");
+       if (fp == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not open the secret key file.\n");
+               return 1;
+       }
+       if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not read the secret key file.\n");
+               fclose(fp);
+               return 1;
+       }
+       fclose(fp);
+
+       CK_BBOOL ckTrue = CK_TRUE;
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_AES;
+       CK_ATTRIBUTE keyTemplate[] = {
+               { CKA_CLASS,            &keyClass,    sizeof(keyClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_SENSITIVE,        &ckTrue,      sizeof(ckTrue) },
+               { CKA_VALUE,            &aesKeyValue, strlen(aesKeyValue) }
+       };
+
+       CK_OBJECT_HANDLE hKey;
+       CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the secret key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+// Import a key pair from given path
+int crypto_import_key_pair
+(
+       CK_SESSION_HANDLE hSession,
+       char* filePath,
+       char* filePIN,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey
+)
+{
+       EVP_PKEY* pkey = crypto_read_file(filePath, filePIN);
+       if (pkey == NULL)
+       {
+               return 1;
+       }
+
+       RSA* rsa = NULL;
+       DSA* dsa = NULL;
+#ifdef WITH_ECC
+       EC_KEY* ecdsa = NULL;
+#endif
+
+       switch (EVP_PKEY_type(EVP_PKEY_id(pkey)))
+       {
+               case EVP_PKEY_RSA:
+                       rsa = EVP_PKEY_get1_RSA(pkey);
+                       break;
+               case EVP_PKEY_DSA:
+                       dsa = EVP_PKEY_get1_DSA(pkey);
+                       break;
+#ifdef WITH_ECC
+               case EVP_PKEY_EC:
+                       ecdsa = EVP_PKEY_get1_EC_KEY(pkey);
+                       break;
+#endif
+               default:
+                       fprintf(stderr, "ERROR: Cannot handle this algorithm.\n");
+                       EVP_PKEY_free(pkey);
+                       return 1;
+                       break;
+       }
+       EVP_PKEY_free(pkey);
+
+       int result = 0;
+
+       if (rsa)
+       {
+               result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa);
+               RSA_free(rsa);
+       }
+       else if (dsa)
+       {
+               result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa);
+               DSA_free(dsa);
+       }
+#ifdef WITH_ECC
+       else if (ecdsa)
+       {
+               result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa);
+               EC_KEY_free(ecdsa);
+       }
+#endif
+       else
+       {
+               fprintf(stderr, "ERROR: Could not get the key material.\n");
+               result = 1;
+       }
+
+       return result;
+}
+
+// Read the key from file
+EVP_PKEY* crypto_read_file(char* filePath, char* filePIN)
+{
+       BIO* in = NULL;
+       PKCS8_PRIV_KEY_INFO* p8inf = NULL;
+       EVP_PKEY* pkey = NULL;
+       X509_SIG* p8 = NULL;
+
+       if (!(in = BIO_new_file(filePath, "rb")))
+       {
+               fprintf(stderr, "ERROR: Could open the PKCS#8 file: %s\n", filePath);
+               return NULL;
+       }
+
+       // The PKCS#8 file is encrypted
+       if (filePIN)
+       {
+               p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL);
+               BIO_free(in);
+
+               if (!p8)
+               {
+                       fprintf(stderr, "ERROR: Could not read the PKCS#8 file. "
+                                       "Maybe the file is not encrypted.\n");
+                       return NULL;
+               }
+
+               p8inf = PKCS8_decrypt(p8, filePIN, strlen(filePIN));
+               X509_SIG_free(p8);
+
+               if (!p8inf)
+               {
+                       fprintf(stderr, "ERROR: Could not decrypt the PKCS#8 file. "
+                                       "Maybe wrong PIN to file (--file-pin <PIN>)\n");
+                       return NULL;
+               }
+       }
+       else
+       {
+               p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL);
+               BIO_free(in);
+
+               if (!p8inf)
+               {
+                       fprintf(stderr, "ERROR: Could not read the PKCS#8 file. "
+                                       "Maybe it is encypted (--file-pin <PIN>)\n");
+                       return NULL;
+               }
+       }
+
+       // Convert the PKCS#8 to OpenSSL
+       pkey = EVP_PKCS82PKEY(p8inf);
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       if (!pkey)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key.\n");
+               return NULL;
+       }
+
+       return pkey;
+}
+
+// Save the key data in PKCS#11
+int crypto_save_rsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       RSA* rsa
+)
+{
+       rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa);
+       if (!keyMat)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_RSA;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,            &pubClass,    sizeof(pubClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckToken,     sizeof(ckToken) },
+               { CKA_VERIFY,           &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_WRAP,             &ckTrue,      sizeof(ckTrue) },
+               { CKA_PUBLIC_EXPONENT,  keyMat->bigE, keyMat->sizeE },
+               { CKA_MODULUS,          keyMat->bigN, keyMat->sizeN }
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,            &privClass,      sizeof(privClass) },
+               { CKA_KEY_TYPE,         &keyType,        sizeof(keyType) },
+               { CKA_LABEL,            label,           strlen(label) },
+               { CKA_ID,               objID,           objIDLen },
+               { CKA_SIGN,             &ckTrue,         sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckTrue,         sizeof(ckTrue) },
+               { CKA_UNWRAP,           &ckTrue,         sizeof(ckTrue) },
+               { CKA_SENSITIVE,        &ckTrue,         sizeof(ckTrue) },
+               { CKA_TOKEN,            &ckTrue,         sizeof(ckTrue) },
+               { CKA_PRIVATE,          &ckTrue,         sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,      &ckFalse,        sizeof(ckFalse) },
+               { CKA_PUBLIC_EXPONENT,  keyMat->bigE,    keyMat->sizeE },
+               { CKA_MODULUS,          keyMat->bigN,    keyMat->sizeN },
+               { CKA_PRIVATE_EXPONENT, keyMat->bigD,    keyMat->sizeD },
+               { CKA_PRIME_1,          keyMat->bigP,    keyMat->sizeP },
+               { CKA_PRIME_2,          keyMat->bigQ,    keyMat->sizeQ },
+               { CKA_EXPONENT_1,       keyMat->bigDMP1, keyMat->sizeDMP1 },
+               { CKA_EXPONENT_2,       keyMat->bigDMQ1, keyMat->sizeDMQ1 },
+               { CKA_COEFFICIENT,      keyMat->bigIQMP, keyMat->sizeIQMP }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_rsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2);
+       crypto_free_rsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the OpenSSL key to binary
+rsa_key_material_t* crypto_malloc_rsa(RSA* rsa)
+{
+       if (rsa == NULL)
+       {
+               return NULL;
+       }
+
+       rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+       const BIGNUM* bn_e = NULL;
+       const BIGNUM* bn_n = NULL;
+       const BIGNUM* bn_d = NULL;
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_dmp1 = NULL;
+       const BIGNUM* bn_dmq1 = NULL;
+       const BIGNUM* bn_iqmp = NULL;
+       RSA_get0_factors(rsa, &bn_p, &bn_q);
+       RSA_get0_crt_params(rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp);
+       RSA_get0_key(rsa, &bn_n, &bn_e, &bn_d);
+
+       keyMat->sizeE = BN_num_bytes(bn_e);
+       keyMat->sizeN = BN_num_bytes(bn_n);
+       keyMat->sizeD = BN_num_bytes(bn_d);
+       keyMat->sizeP = BN_num_bytes(bn_p);
+       keyMat->sizeQ = BN_num_bytes(bn_q);
+       keyMat->sizeDMP1 = BN_num_bytes(bn_dmp1);
+       keyMat->sizeDMQ1 = BN_num_bytes(bn_dmq1);
+       keyMat->sizeIQMP = BN_num_bytes(bn_iqmp);
+
+       keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE);
+       keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN);
+       keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD);
+       keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP);
+       keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+       keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1);
+       keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1);
+       keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP);
+
+       if
+       (
+               !keyMat->bigE ||
+               !keyMat->bigN ||
+               !keyMat->bigD ||
+               !keyMat->bigP ||
+               !keyMat->bigQ ||
+               !keyMat->bigDMP1 ||
+               !keyMat->bigDMQ1 ||
+               !keyMat->bigIQMP
+       )
+       {
+               crypto_free_rsa(keyMat);
+               return NULL;
+       }
+
+       BN_bn2bin(bn_e, (unsigned char*)keyMat->bigE);
+       BN_bn2bin(bn_n, (unsigned char*)keyMat->bigN);
+       BN_bn2bin(bn_d, (unsigned char*)keyMat->bigD);
+       BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP);
+       BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ);
+       BN_bn2bin(bn_dmp1, (unsigned char*)keyMat->bigDMP1);
+       BN_bn2bin(bn_dmq1, (unsigned char*)keyMat->bigDMQ1);
+       BN_bn2bin(bn_iqmp, (unsigned char*)keyMat->bigIQMP);
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_rsa(rsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->bigE) free(keyMat->bigE);
+       if (keyMat->bigN) free(keyMat->bigN);
+       if (keyMat->bigD) free(keyMat->bigD);
+       if (keyMat->bigP) free(keyMat->bigP);
+       if (keyMat->bigQ) free(keyMat->bigQ);
+       if (keyMat->bigDMP1) free(keyMat->bigDMP1);
+       if (keyMat->bigDMQ1) free(keyMat->bigDMQ1);
+       if (keyMat->bigIQMP) free(keyMat->bigIQMP);
+       free(keyMat);
+}
+
+// Save the key data in PKCS#11
+int crypto_save_dsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       DSA* dsa
+)
+{
+       dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa);
+       if (keyMat == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_DSA;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,            &pubClass,    sizeof(pubClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_TOKEN,            &ckToken,     sizeof(ckToken) },
+               { CKA_VERIFY,           &ckTrue,      sizeof(ckTrue) },
+               { CKA_ENCRYPT,          &ckFalse,     sizeof(ckFalse) },
+               { CKA_WRAP,             &ckFalse,     sizeof(ckFalse) },
+               { CKA_PRIME,            keyMat->bigP, keyMat->sizeP },
+               { CKA_SUBPRIME,         keyMat->bigQ, keyMat->sizeQ },
+               { CKA_BASE,             keyMat->bigG, keyMat->sizeG },
+               { CKA_VALUE,            keyMat->bigY, keyMat->sizeY }
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,            &privClass,   sizeof(privClass) },
+               { CKA_KEY_TYPE,         &keyType,     sizeof(keyType) },
+               { CKA_LABEL,            label,        strlen(label) },
+               { CKA_ID,               objID,        objIDLen },
+               { CKA_SIGN,             &ckTrue,      sizeof(ckTrue) },
+               { CKA_DECRYPT,          &ckFalse,     sizeof(ckFalse) },
+               { CKA_UNWRAP,           &ckFalse,     sizeof(ckFalse) },
+               { CKA_SENSITIVE,        &ckTrue,      sizeof(ckTrue) },
+               { CKA_TOKEN,            &ckTrue,      sizeof(ckTrue) },
+               { CKA_PRIVATE,          &ckTrue,      sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,      &ckFalse,     sizeof(ckFalse) },
+               { CKA_PRIME,            keyMat->bigP, keyMat->sizeP },
+               { CKA_SUBPRIME,         keyMat->bigQ, keyMat->sizeQ },
+               { CKA_BASE,             keyMat->bigG, keyMat->sizeG },
+               { CKA_VALUE,            keyMat->bigX, keyMat->sizeX }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_dsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2);
+       crypto_free_dsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the OpenSSL key to binary
+dsa_key_material_t* crypto_malloc_dsa(DSA* dsa)
+{
+       if (dsa == NULL)
+       {
+               return NULL;
+       }
+
+       dsa_key_material_t* keyMat = (dsa_key_material_t*)malloc(sizeof(dsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_g = NULL;
+       const BIGNUM* bn_priv_key = NULL;
+       const BIGNUM* bn_pub_key = NULL;
+       DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g);
+       DSA_get0_key(dsa, &bn_pub_key, &bn_priv_key);
+
+       keyMat->sizeP = BN_num_bytes(bn_p);
+       keyMat->sizeQ = BN_num_bytes(bn_q);
+       keyMat->sizeG = BN_num_bytes(bn_g);
+       keyMat->sizeX = BN_num_bytes(bn_priv_key);
+       keyMat->sizeY = BN_num_bytes(bn_pub_key);
+
+       keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP);
+       keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+       keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG);
+       keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX);
+       keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY);
+
+       if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY)
+       {
+               crypto_free_dsa(keyMat);
+               return NULL;
+       }
+
+       BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP);
+       BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ);
+       BN_bn2bin(bn_g, (unsigned char*)keyMat->bigG);
+       BN_bn2bin(bn_priv_key, (unsigned char*)keyMat->bigX);
+       BN_bn2bin(bn_pub_key, (unsigned char*)keyMat->bigY);
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_dsa(dsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->bigP) free(keyMat->bigP);
+       if (keyMat->bigQ) free(keyMat->bigQ);
+       if (keyMat->bigG) free(keyMat->bigG);
+       if (keyMat->bigX) free(keyMat->bigX);
+       if (keyMat->bigY) free(keyMat->bigY);
+       free(keyMat);
+}
+
+#ifdef WITH_ECC
+
+// Save the key data in PKCS#11
+int crypto_save_ecdsa
+(
+       CK_SESSION_HANDLE hSession,
+       char* label,
+       char* objID,
+       size_t objIDLen,
+       int noPublicKey,
+       EC_KEY* ecdsa
+)
+{
+       ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa);
+       if (keyMat == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n");
+               return 1;
+       }
+
+       CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE keyType = CKK_EC;
+       CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
+       if (noPublicKey)
+       {
+               ckToken = CK_FALSE;
+       }
+       CK_ATTRIBUTE pubTemplate[] = {
+               { CKA_CLASS,          &pubClass,         sizeof(pubClass) },
+               { CKA_KEY_TYPE,       &keyType,          sizeof(keyType) },
+               { CKA_LABEL,          label,             strlen(label) },
+               { CKA_ID,             objID,             objIDLen },
+               { CKA_TOKEN,          &ckToken,          sizeof(ckToken) },
+               { CKA_VERIFY,         &ckTrue,           sizeof(ckTrue) },
+               { CKA_ENCRYPT,        &ckFalse,          sizeof(ckFalse) },
+               { CKA_WRAP,           &ckFalse,          sizeof(ckFalse) },
+               { CKA_EC_PARAMS,      keyMat->derParams, keyMat->sizeParams },
+               { CKA_EC_POINT,       keyMat->derQ,      keyMat->sizeQ },
+       };
+       CK_ATTRIBUTE privTemplate[] = {
+               { CKA_CLASS,          &privClass,        sizeof(privClass) },
+               { CKA_KEY_TYPE,       &keyType,          sizeof(keyType) },
+               { CKA_LABEL,          label,             strlen(label) },
+               { CKA_ID,             objID,             objIDLen },
+               { CKA_SIGN,           &ckTrue,           sizeof(ckTrue) },
+               { CKA_DECRYPT,        &ckFalse,          sizeof(ckFalse) },
+               { CKA_UNWRAP,         &ckFalse,          sizeof(ckFalse) },
+               { CKA_SENSITIVE,      &ckTrue,           sizeof(ckTrue) },
+               { CKA_TOKEN,          &ckTrue,           sizeof(ckTrue) },
+               { CKA_PRIVATE,        &ckTrue,           sizeof(ckTrue) },
+               { CKA_EXTRACTABLE,    &ckFalse,          sizeof(ckFalse) },
+               { CKA_EC_PARAMS,      keyMat->derParams, keyMat->sizeParams },
+               { CKA_VALUE,          keyMat->bigD,      keyMat->sizeD }
+       };
+
+       CK_OBJECT_HANDLE hKey1, hKey2;
+       CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not save the private key in the token. "
+                               "Maybe the algorithm is not supported.\n");
+               crypto_free_ecdsa(keyMat);
+               return 1;
+       }
+
+       rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2);
+       crypto_free_ecdsa(keyMat);
+
+       if (rv != CKR_OK)
+       {
+               p11->C_DestroyObject(hSession, hKey1);
+               fprintf(stderr, "ERROR: Could not save the public key in the token.\n");
+               return 1;
+       }
+
+       printf("The key pair has been imported.\n");
+
+       return 0;
+}
+
+// Convert the OpenSSL key to binary
+ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ec_key)
+{
+       int result;
+
+       if (ec_key == NULL)
+       {
+               return NULL;
+       }
+
+       ecdsa_key_material_t* keyMat = (ecdsa_key_material_t*)malloc(sizeof(ecdsa_key_material_t));
+       if (keyMat == NULL)
+       {
+               return NULL;
+       }
+
+       const BIGNUM *d = EC_KEY_get0_private_key(ec_key);
+       const EC_GROUP *group = EC_KEY_get0_group(ec_key);
+       const EC_POINT *point = EC_KEY_get0_public_key(ec_key);
+
+       keyMat->sizeParams = i2d_ECPKParameters(group, NULL);
+       keyMat->sizeD = BN_num_bytes(d);
+
+       keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams);
+       keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD);
+       keyMat->derQ = NULL;
+
+       if (!keyMat->derParams || !keyMat->bigD)
+       {
+               crypto_free_ecdsa(keyMat);
+               return NULL;
+       }
+
+       /*
+        * i2d functions increment the pointer, so we have to use a
+        * sacrificial pointer
+        */
+       unsigned char *derParams = (unsigned char*) keyMat->derParams;
+       result = i2d_ECPKParameters(group, &derParams);
+       if (result == 0)
+       {
+               crypto_free_ecdsa(keyMat);
+               return NULL;
+       }
+       BN_bn2bin(d, (unsigned char*)keyMat->bigD);
+
+       size_t point_length = EC_POINT_point2oct(group,
+                                             point,
+                                             POINT_CONVERSION_UNCOMPRESSED,
+                                             NULL,
+                                             0,
+                                             NULL);
+
+       // Definite, short
+       if (point_length <= 0x7f)
+       {
+               keyMat->sizeQ = 2 + point_length;
+               keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+               if (!keyMat->derQ)
+               {
+                       crypto_free_ecdsa(keyMat);
+                       return NULL;
+               }
+
+               unsigned char *derQ = (unsigned char *)keyMat->derQ;
+               derQ[0] = V_ASN1_OCTET_STRING;
+               derQ[1] = point_length & 0x7f;
+               result = EC_POINT_point2oct(group,
+                                           point,
+                                           POINT_CONVERSION_UNCOMPRESSED,
+                                           &derQ[2],
+                                           point_length,
+                                           NULL);
+               if (result == 0)
+               {
+                       crypto_free_ecdsa(keyMat);
+                       return NULL;
+               }
+       }
+       // Definite, long
+       else
+       {
+               // Count significate bytes
+               size_t bytes = sizeof(size_t);
+               for(; bytes > 0; bytes--)
+               {
+                       size_t value = point_length >> ((bytes - 1) * 8);
+                       if (value & 0xFF) break;
+               }
+
+               keyMat->sizeQ = 2 + bytes + point_length;
+               keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ);
+               if (!keyMat->derQ)
+               {
+                       crypto_free_ecdsa(keyMat);
+                       return NULL;
+               }
+
+               unsigned char *derQ = (unsigned char *)keyMat->derQ;
+               derQ[0] = V_ASN1_OCTET_STRING;
+               derQ[1] = 0x80 | bytes;
+
+               size_t len = point_length;
+               for (size_t i = 1; i <= bytes; i++)
+               {
+                       derQ[2+bytes-i] = (unsigned char) (len & 0xFF);
+                       len >>= 8;
+               }
+
+               result = EC_POINT_point2oct(group,
+                                           point,
+                                           POINT_CONVERSION_UNCOMPRESSED,
+                                           &derQ[2+bytes],
+                                           point_length,
+                                           NULL);
+               if (result == 0)
+               {
+                       crypto_free_ecdsa(keyMat);
+                       return NULL;
+               }
+       }
+
+       return keyMat;
+}
+
+// Free the memory of the key
+void crypto_free_ecdsa(ecdsa_key_material_t* keyMat)
+{
+       if (keyMat == NULL) return;
+       if (keyMat->derParams) free(keyMat->derParams);
+       if (keyMat->bigD) free(keyMat->bigD);
+       if (keyMat->derQ) free(keyMat->derQ);
+       free(keyMat);
+}
+
+#endif
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h
new file mode 100644 (file)
index 0000000..7a2a31a
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util-ossl.h
+
+ Header file for OpenSSL implemented
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H
+#define _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#ifdef WITH_ECC
+#include <openssl/ec.h>
+#endif
+
+typedef struct rsa_key_material_t {
+       CK_ULONG sizeE;
+       CK_ULONG sizeN;
+       CK_ULONG sizeD;
+       CK_ULONG sizeP;
+       CK_ULONG sizeQ;
+       CK_ULONG sizeDMP1;
+       CK_ULONG sizeDMQ1;
+       CK_ULONG sizeIQMP;
+       CK_VOID_PTR bigE;
+       CK_VOID_PTR bigN;
+       CK_VOID_PTR bigD;
+       CK_VOID_PTR bigP;
+       CK_VOID_PTR bigQ;
+       CK_VOID_PTR bigDMP1;
+       CK_VOID_PTR bigDMQ1;
+       CK_VOID_PTR bigIQMP;
+       rsa_key_material_t() {
+               sizeE = 0;
+               sizeN = 0;
+               sizeD = 0;
+               sizeP = 0;
+               sizeQ = 0;
+               sizeDMP1 = 0;
+               sizeDMQ1 = 0;
+               sizeIQMP = 0;
+               bigE = NULL_PTR;
+               bigN = NULL_PTR;
+               bigD = NULL_PTR;
+               bigP = NULL_PTR;
+               bigQ = NULL_PTR;
+               bigDMP1 = NULL_PTR;
+               bigDMQ1 = NULL_PTR;
+               bigIQMP = NULL_PTR;
+       }
+} rsa_key_material_t;
+
+typedef struct dsa_key_material_t {
+       CK_ULONG sizeP;
+       CK_ULONG sizeQ;
+       CK_ULONG sizeG;
+       CK_ULONG sizeX;
+       CK_ULONG sizeY;
+       CK_VOID_PTR bigP;
+       CK_VOID_PTR bigQ;
+       CK_VOID_PTR bigG;
+       CK_VOID_PTR bigX;
+       CK_VOID_PTR bigY;
+       dsa_key_material_t() {
+               sizeP = 0;
+               sizeQ = 0;
+               sizeG = 0;
+               sizeX = 0;
+               sizeY = 0;
+               bigP = NULL_PTR;
+               bigQ = NULL_PTR;
+               bigG = NULL_PTR;
+               bigX = NULL_PTR;
+               bigY = NULL_PTR;
+       }
+} dsa_key_material_t;
+
+#ifdef WITH_ECC
+typedef struct ecdsa_key_material_t {
+       CK_ULONG sizeParams;
+       CK_ULONG sizeD;
+       CK_ULONG sizeQ;
+       CK_VOID_PTR derParams;
+       CK_VOID_PTR bigD;
+       CK_VOID_PTR derQ;
+       ecdsa_key_material_t() {
+               sizeParams = 0;
+               sizeD = 0;
+               sizeQ = 0;
+               derParams = NULL_PTR;
+               bigD = NULL_PTR;
+               derQ = NULL_PTR;
+       }
+} ecdsa_key_material_t;
+#endif
+
+EVP_PKEY* crypto_read_file(char* filePath, char* filePIN);
+
+// RSA
+int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, RSA* rsa);
+rsa_key_material_t* crypto_malloc_rsa(RSA* rsa);
+void crypto_free_rsa(rsa_key_material_t* keyMat);
+
+// DSA
+int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, DSA* dsa);
+dsa_key_material_t* crypto_malloc_dsa(DSA* dsa);
+void crypto_free_dsa(dsa_key_material_t* keyMat);
+
+#ifdef WITH_ECC
+// ECDSA
+int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, EC_KEY* ecdsa);
+ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ecdsa);
+void crypto_free_ecdsa(ecdsa_key_material_t* keyMat);
+#endif
+
+#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.1 b/SoftHSMv2/src/bin/util/softhsm2-util.1
new file mode 100644 (file)
index 0000000..1998226
--- /dev/null
@@ -0,0 +1,259 @@
+.TH SOFTHSM2-UTIL 1 "22 September 2017" "SoftHSM"
+.SH NAME
+softhsm2-util \- support tool for libsofthsm2
+.SH SYNOPSIS
+.B softhsm2-util \-\-show-slots
+.PP
+.B softhsm2-util \-\-init-token
+.B \-\-free
+.B \-\-label
+.I text
+\\
+.ti +0.7i
+.RB [ \-\-so-pin
+.I PIN
+.B \-\-pin
+.IR PIN ]
+.PP
+.B softhsm2-util \-\-import
+.I path
+.RB [ \-\-file-pin
+.IR PIN ]
+.B \-\-token
+.I label
+\\
+.ti +0.7i
+.RB [ \-\-pin
+.I PIN
+.B \-\-no\-public\-key]
+.B \-\-label
+.I text
+.B \-\-id
+.I hex
+.PP
+.B softhsm2-util \-\-import
+.I path
+.B \-\-aes
+.B \-\-token
+.I label
+\\
+.ti +0.7i
+.RB [ \-\-pin
+.I PIN]
+.B \-\-label
+.I text
+.B \-\-id
+.I hex
+.PP
+.B softhsm2-util \-\-delete\-token
+.B \-\-token
+.I text
+.SH DESCRIPTION
+.B softhsm2-util
+is a support tool mainly for libsofthsm2. It can also
+be used with other PKCS#11 libraries by using the option
+.B \-\-module
+.PP
+Read the sections below to get more information on
+the libsofthsm2 and PKCS#11.
+Most applications assumes that the token they want
+to use is already initialized.
+It is then up to the user
+to initialize the PKCS#11 token.
+This is done by using the PKCS#11 interface,
+but instead of writing your own
+tool you can use the
+.B softhsm2-util
+tool.
+.PP
+Keys are usually created directly in the token,
+but the user may want to use an existing key pair.
+Keys can be imported to a token by using the PKCS#11 interface,
+but this tool can also be used if the
+user has the key pair in a PKCS#8 file.
+If you need to convert keys from
+BIND .private-key format over to PKCS#8,
+one can
+use
+.BR softhsm2-keyconv .
+.LP
+The libary
+.BR libsofthsm2 ,
+known as SoftHSM, provides cryptographic functionality
+by using the PKCS#11 API.
+It was developed as a part of the OpenDNSSEC project,
+thus designed to meet the requirements
+of OpenDNSSEC,
+but can also work together with other
+software that want to use the functionality
+of the PKCS#11 API.
+.PP
+SoftHSM is a software implementation of a generic cryptographic device with a PKCS#11 interface.
+These devices are often called tokens.
+Read in the manual softhsm2.conf(5) on how to create these
+tokens and how they are added to a slot in SoftHSM.
+.LP
+The 
+.B PKCS#11
+API
+can be used to handle and store cryptographic keys.
+This interface
+specifies how to communicate with cryptographic devices such as HSMs
+(Hardware Security Modules) and smart cards.
+The purpose of these devices
+is, among others,
+to generate cryptographic keys and sign information without
+revealing private-key material to the outside world.
+They are often designed
+to perform well on these specific tasks
+compared to ordinary processes in a normal computer.
+.LP
+.SH ACTIONS
+.TP
+.B \-\-delete\-token
+Delete the token at a given slot.
+Use with
+.BR \-\-token
+or
+.BR \-\-serial .
+Any content in token will be erased.
+.TP
+.B \-\-help\fR, \fB\-h\fR
+Show the help information.
+.TP
+.B \-\-import \fIpath\fR
+Import a key pair from the given
+.IR path .
+The file must be in PKCS#8-format.
+.br
+Use with
+.BR \-\-slot
+or
+.BR \-\-token
+or
+.BR \-\-serial ,
+.BR \-\-file-pin ,
+.BR \-\-pin ,
+.BR \-\-no\-public\-key ,
+.BR \-\-label ,
+and
+.BR \-\-id .
+.br
+Can also be used with
+.BR \-\-aes
+to use file as is and import it as AES.
+.TP
+.B \-\-init-token
+Initialize the token at a given slot, token label or token serial.
+If the token is already initialized then this command
+will reinitialize it, thus erasing all the objects in the token.
+The matching Security Officer (SO) PIN must also
+be provided when doing reinitialization.
+Initialized tokens will be reassigned to another slot (based on
+the token serial number).
+.br
+Use with
+.BR \-\-slot
+or
+.BR \-\-token
+or
+.BR \-\-serial
+or
+.BR \-\-free ,
+.BR \-\-label ,
+.BR \-\-so-pin ,
+and
+.BR \-\-pin .
+.LP
+.TP
+.B \-\-show-slots
+Display all the available slots and their current status.
+.TP
+.B \-\-version\fR, \fB\-v\fR
+Show the version info.
+.SH OPTIONS
+.TP
+.B \-\-aes
+Used to tell import to use file as is and import it as AES.
+.TP
+.B \-\-file-pin \fIPIN\fR
+The
+.I PIN
+will be used to decrypt the PKCS#8 file.
+If not given then the PKCS#8 file is assumed to be unencrypted.
+.TP
+.B \-\-force 
+Use this option to override the warnings and force the given action.
+.TP
+.B \-\-free
+Use the first free/uninitialized token.
+.TP
+.B \-\-id \fIhex\fR
+Choose an ID of the key pair.
+The ID is in hexadecimal with a variable length.
+Use with
+.B \-\-force 
+when importing a key pair if the ID already exists.
+.TP
+.B \-\-label \fItext\fR
+Defines the
+.I label
+of the object or the token that will be set.
+.TP
+.B \-\-module \fIpath\fR
+Use another PKCS#11 library than SoftHSM.
+.TP
+.B \-\-no\-public\-key
+Do not import the public key.
+.TP
+.B \-\-pin \fIPIN\fR
+The
+.I PIN
+for the normal user.
+.TP
+.B \-\-serial \fInumber\fR
+Will use the token with a matching serial number.
+.TP
+.B \-\-slot \fInumber\fR
+The slot where the token is located.
+.TP
+.B \-\-so-pin \fIPIN\fR
+The
+.I PIN
+for the Security Officer (SO).
+.TP
+.B \-\-token \fIlabel\fR
+Will use the token with a matching token label.
+.SH EXAMPLES
+.LP
+The token can be initialized using this command:
+.LP
+.RS
+.nf
+softhsm2-util \-\-init-token \-\-slot 1 \-\-label "mytoken"
+.fi
+.RE
+.LP
+A key pair can be imported using the softhsm tool where you specify the path
+to the key file, slot number, label and ID of the new objects, and the
+user PIN.
+The file must be in PKCS#8 format.
+.LP
+.RS
+.nf
+softhsm2-util \-\-import key1.pem \-\-token "mytoken" \-\-label "My key" \\
+.ti +0.7i
+\-\-id A1B2 \-\-pin 123456
+.fi
+(Add, \-\-file-pin
+.IR PIN ,
+if the key file is encrypted.)
+.RE
+.LP
+.SH AUTHORS
+Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk.
+.LP
+.SH "SEE ALSO"
+.IR softhsm2-keyconv (1),
+.IR softhsm2-migrate (1),
+.IR softhsm2.conf (5)
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.cpp b/SoftHSMv2/src/bin/util/softhsm2-util.cpp
new file mode 100644 (file)
index 0000000..465df4a
--- /dev/null
@@ -0,0 +1,1318 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util.cpp
+
+ This program can be used for interacting with HSMs using PKCS#11.
+ The default library is the libsofthsm2.so
+ *****************************************************************************/
+
+#include <config.h>
+#include "softhsm2-util.h"
+#include "findslot.h"
+#include "getpw.h"
+#include "library.h"
+#include "log.h"
+#include "Configuration.h"
+#include "SimpleConfigLoader.h"
+#include "Directory.h"
+#include "MutexFactory.h"
+#include "ObjectStoreToken.h"
+#include "OSPathSep.h"
+
+#if defined(WITH_OPENSSL)
+#include "OSSLCryptoFactory.h"
+#else
+#include "BotanCryptoFactory.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#else
+#include <direct.h>
+#include <io.h>
+#endif
+#include <iostream>
+#include <fstream>
+
+// 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
+
+// Display the usage
+void usage()
+{
+       printf("Support tool for PKCS#11\n");
+       printf("Usage: softhsm2-util [ACTION] [OPTIONS]\n");
+       printf("Action:\n");
+       printf("  --delete-token    Delete the token at a given slot.\n");
+       printf("                    Use with --token or --serial.\n");
+       printf("                    WARNING: Any content in token will be erased.\n");
+       printf("  -h                Shows this help screen.\n");
+       printf("  --help            Shows this help screen.\n");
+       printf("  --import <path>   Import a key pair from the given path.\n");
+       printf("                    The file must be in PKCS#8-format.\n");
+       printf("                    Use with --slot or --token or --serial, --file-pin,\n");
+       printf("                    --label, --id, --no-public-key, and --pin.\n");
+       printf("  --init-token      Initialize the token at a given slot.\n");
+       printf("                    Use with --slot or --token or --serial or --free,\n");
+       printf("                    --label, --so-pin, and --pin.\n");
+       printf("                    WARNING: Any content in token will be erased.\n");
+       printf("  --show-slots      Display all the available slots.\n");
+       printf("  -v                Show version info.\n");
+       printf("  --version         Show version info.\n");
+       printf("Options:\n");
+       printf("  --aes             Used to tell import to use file as is and import it as AES.\n");
+       printf("  --file-pin <PIN>  Supply a PIN if the file is encrypted.\n");
+       printf("  --force           Used to override a warning.\n");
+       printf("  --free            Use the first free/uninitialized token.\n");
+       printf("  --id <hex>        Defines the ID of the object. Hexadecimal characters.\n");
+       printf("                    Use with --force if multiple key pairs may share\n");
+       printf("                    the same ID.\n");
+       printf("  --label <text>    Defines the label of the object or the token.\n");
+       printf("  --module <path>   Use another PKCS#11 library than SoftHSM.\n");
+       printf("  --no-public-key   Do not import the public key.\n");
+       printf("  --pin <PIN>       The PIN for the normal user.\n");
+       printf("  --serial <number> Will use the token with a matching serial number.\n");
+       printf("  --slot <number>   The slot where the token is located.\n");
+       printf("  --so-pin <PIN>    The PIN for the Security Officer (SO).\n");
+       printf("  --token <label>   Will use the token with a matching token label.\n");
+}
+
+// Enumeration of the long options
+enum {
+       OPT_DELETE_TOKEN = 0x100,
+       OPT_FILE_PIN,
+       OPT_FORCE,
+       OPT_FREE,
+       OPT_HELP,
+       OPT_ID,
+       OPT_IMPORT,
+       OPT_INIT_TOKEN,
+       OPT_LABEL,
+       OPT_MODULE,
+       OPT_NO_PUBLIC_KEY,
+       OPT_PIN,
+       OPT_SERIAL,
+       OPT_SHOW_SLOTS,
+       OPT_SLOT,
+       OPT_SO_PIN,
+       OPT_TOKEN,
+       OPT_VERSION,
+       OPT_AES
+};
+
+// Text representation of the long options
+static const struct option long_options[] = {
+       { "delete-token",    0, NULL, OPT_DELETE_TOKEN },
+       { "file-pin",        1, NULL, OPT_FILE_PIN },
+       { "force",           0, NULL, OPT_FORCE },
+       { "free",            0, NULL, OPT_FREE },
+       { "help",            0, NULL, OPT_HELP },
+       { "id",              1, NULL, OPT_ID },
+       { "import",          1, NULL, OPT_IMPORT },
+       { "init-token",      0, NULL, OPT_INIT_TOKEN },
+       { "label",           1, NULL, OPT_LABEL },
+       { "module",          1, NULL, OPT_MODULE },
+       { "no-public-key",   0, NULL, OPT_NO_PUBLIC_KEY },
+       { "pin",             1, NULL, OPT_PIN },
+       { "serial",          1, NULL, OPT_SERIAL },
+       { "show-slots",      0, NULL, OPT_SHOW_SLOTS },
+       { "slot",            1, NULL, OPT_SLOT },
+       { "so-pin",          1, NULL, OPT_SO_PIN },
+       { "token",           1, NULL, OPT_TOKEN },
+       { "version",         0, NULL, OPT_VERSION },
+       { "aes",             0, NULL, OPT_AES },
+       { NULL,              0, NULL, 0 }
+};
+
+CK_FUNCTION_LIST_PTR p11;
+
+// The main function
+int main(int argc, char* argv[])
+{
+       int option_index = 0;
+       int opt;
+
+       char* inPath = NULL;
+       char* soPIN = NULL;
+       char* userPIN = NULL;
+       char* filePIN = NULL;
+       char* label = NULL;
+       char* module = NULL;
+       char* objectID = NULL;
+       char* slot = NULL;
+       char* serial = NULL;
+       char* token = NULL;
+       char* errMsg = NULL;
+       int forceExec = 0;
+       bool freeToken = false;
+       int noPublicKey = 0;
+       bool importAES = false;
+
+       int doInitToken = 0;
+       int doShowSlots = 0;
+       int doImport = 0;
+       int doDeleteToken = 0;
+       int action = 0;
+       bool needP11 = false;
+       int rv = 0;
+       CK_SLOT_ID slotID = 0;
+
+       moduleHandle = NULL;
+       p11 = NULL;
+
+       while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
+       {
+               switch (opt)
+               {
+                       case OPT_SHOW_SLOTS:
+                               doShowSlots = 1;
+                               action++;
+                               needP11 = true;
+                               break;
+                       case OPT_INIT_TOKEN:
+                               doInitToken = 1;
+                               action++;
+                               needP11 = true;
+                               break;
+                       case OPT_IMPORT:
+                               doImport = 1;
+                               action++;
+                               inPath = optarg;
+                               needP11 = true;
+                               break;
+                       case OPT_AES:
+                               importAES = true;
+                               break;
+                       case OPT_DELETE_TOKEN:
+                               doDeleteToken = 1;
+                               action++;
+                               break;
+                       case OPT_SLOT:
+                               slot = optarg;
+                               break;
+                       case OPT_LABEL:
+                               label = optarg;
+                               break;
+                       case OPT_SERIAL:
+                               serial = optarg;
+                               break;
+                       case OPT_TOKEN:
+                               token = optarg;
+                               break;
+                       case OPT_MODULE:
+                               module = optarg;
+                               break;
+                       case OPT_NO_PUBLIC_KEY:
+                               noPublicKey = 1;
+                               break;
+                       case OPT_ID:
+                               objectID = optarg;
+                               break;
+                       case OPT_SO_PIN:
+                               soPIN = optarg;
+                               break;
+                       case OPT_PIN:
+                               userPIN = optarg;
+                               break;
+                       case OPT_FILE_PIN:
+                               filePIN = optarg;
+                               break;
+                       case OPT_FORCE:
+                               forceExec = 1;
+                               break;
+                       case OPT_FREE:
+                               freeToken = true;
+                               break;
+                       case OPT_VERSION:
+                       case 'v':
+                               printf("%s\n", PACKAGE_VERSION);
+                               exit(0);
+                               break;
+                       case OPT_HELP:
+                       case 'h':
+                       default:
+                               usage();
+                               exit(0);
+                               break;
+               }
+       }
+
+       // No action given, display the usage.
+       if (action != 1)
+       {
+               usage();
+               exit(1);
+       }
+
+       if (needP11)
+       {
+               // Check the basic setup of SoftHSM
+               if (!checkSetup())
+               {
+                       fprintf(stderr, "ERROR: Please verify that the SoftHSM configuration is correct.\n");
+                       exit(1);
+               }
+
+               // Get a pointer to the function list for PKCS#11 library
+               CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg);
+               if (!pGetFunctionList)
+               {
+                       fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg);
+                       fprintf(stderr, "ERROR: Please check log files for additional information.\n");
+                       exit(1);
+               }
+
+               // Load the function list
+               (*pGetFunctionList)(&p11);
+
+               // Initialize the library
+               CK_RV p11rv = p11->C_Initialize(NULL_PTR);
+               if (p11rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB);
+                       fprintf(stderr, "ERROR: Please check log files for additional information.\n");
+                       exit(1);
+               }
+       }
+
+       // We should create the token.
+       if (doInitToken)
+       {
+               // Get the slotID
+               rv = findSlot(slot, serial, token, freeToken, slotID);
+               if (!rv)
+               {
+                       rv = initToken(slotID, label, soPIN, userPIN);
+               }
+       }
+
+       // Show all available slots
+       if (!rv && doShowSlots)
+       {
+               rv = showSlots();
+       }
+
+       // Import a key pair from the given path
+       if (!rv && doImport)
+       {
+               // Get the slotID
+               rv = findSlot(slot, serial, token, slotID);
+               if (!rv)
+               {
+                       rv = importAES ? importSecretKey(inPath, slotID, userPIN, label, objectID)
+                                       : importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey);
+               }
+       }
+
+       // We should delete the token.
+       if (!rv && doDeleteToken)
+       {
+               if (deleteToken(serial, token))
+               {
+                       rv = 0;
+               }
+               else
+               {
+                       rv = 1;
+               }
+       }
+
+       // Finalize the library
+       if (needP11)
+       {
+               p11->C_Finalize(NULL_PTR);
+               unloadLibrary(moduleHandle);
+       }
+
+       return rv;
+}
+
+// Check the basic setup of SoftHSM
+bool checkSetup()
+{
+       // Initialize the SoftHSM internal functions
+       if (!initSoftHSM())
+       {
+               finalizeSoftHSM();
+               return false;
+       }
+
+       std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR);
+
+       // Try open the token directory
+       Directory storeDir(basedir);
+       if (!storeDir.isValid())
+       {
+               fprintf(stderr, "ERROR: Failed to enumerate object store in %s\n", basedir.c_str());
+               finalizeSoftHSM();
+               return false;
+       }
+
+       finalizeSoftHSM();
+       return true;
+}
+
+// Initialize the token
+int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN)
+{
+       char so_pin_copy[MAX_PIN_LEN+1];
+       char user_pin_copy[MAX_PIN_LEN+1];
+
+       if (label == NULL)
+       {
+               fprintf(stderr, "ERROR: A label for the token must be supplied. "
+                               "Use --label <text>\n");
+               return 1;
+       }
+
+       if (strlen(label) > 32)
+       {
+               fprintf(stderr, "ERROR: The token label must not have a length "
+                               "greater than 32 chars.\n");
+               return 1;
+       }
+
+       // Get the passwords
+       if (getPW(soPIN, so_pin_copy, CKU_SO) != 0)
+       {
+               fprintf(stderr, "ERROR: Could not get SO PIN\n");
+               return 1;
+       }
+       if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
+       {
+               fprintf(stderr, "ERROR: Could not get user PIN\n");
+               return 1;
+       }
+
+       // Load the variables
+       CK_UTF8CHAR paddedLabel[32];
+       memset(paddedLabel, ' ', sizeof(paddedLabel));
+       memcpy(paddedLabel, label, strlen(label));
+
+       CK_RV rv = p11->C_InitToken(slotID, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy), paddedLabel);
+
+       switch (rv)
+       {
+               case CKR_OK:
+                       break;
+               case CKR_SLOT_ID_INVALID:
+                       fprintf(stderr, "CKR_SLOT_ID_INVALID: Slot %lu does not exist.\n", slotID);
+                       return 1;
+                       break;
+               case CKR_PIN_INCORRECT:
+                       fprintf(stderr, "CKR_PIN_INCORRECT: The given SO PIN does not match the "
+                                       "one in the token. Needed when reinitializing the token.\n");
+                       return 1;
+                       break;
+               case CKR_TOKEN_NOT_PRESENT:
+                       fprintf(stderr, "CKR_TOKEN_NOT_PRESENT: The token is not present. "
+                                       "Please read the HSM manual for further assistance.\n");
+                       return 1;
+                       break;
+               default:
+                       fprintf(stderr, "ERROR rv=0x%08X: Could not initialize the token.\n", (unsigned int)rv);
+                       fprintf(stderr, "Please check log files for additional information.\n");
+                       return 1;
+                       break;
+       }
+
+       CK_SESSION_HANDLE hSession;
+       rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not open a session with the library.\n");
+               return 1;
+       }
+
+       rv = p11->C_Login(hSession, CKU_SO, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy));
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not log in on the token.\n");
+               return 1;
+       }
+
+       rv = p11->C_InitPIN(hSession, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not initialize the user PIN.\n");
+               return 1;
+       }
+
+       // Get the token info
+       CK_TOKEN_INFO tokenInfo;
+       rv = p11->C_GetTokenInfo(slotID, &tokenInfo);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get info about the initialized token in slot %lu.\n", slotID);
+               return 1;
+       }
+
+       // Reload the library
+       p11->C_Finalize(NULL_PTR);
+       rv = p11->C_Initialize(NULL_PTR);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not initialize the library.\n");
+               return 1;
+       }
+
+       // Get the slotID
+       CK_SLOT_ID newSlotID;
+       if (findSlot(tokenInfo, newSlotID))
+       {
+               return 1;
+       }
+
+       if (slotID == newSlotID)
+       {
+               printf("The token has been initialized on slot %lu\n", newSlotID);
+       }
+       else
+       {
+               printf("The token has been initialized and is reassigned to slot %lu\n", newSlotID);
+       }
+
+       return 0;
+}
+
+// Delete the token
+bool deleteToken(char* serial, char* token)
+{
+       if (serial == NULL && token == NULL)
+       {
+               fprintf(stderr, "ERROR: A token must be supplied. "
+                               "Use --serial <serial> or --token <label>\n");
+               return false;
+       }
+
+       // Initialize the SoftHSM internal functions
+       if (!initSoftHSM())
+       {
+               finalizeSoftHSM();
+               return false;
+       }
+
+       bool rv = true;
+       std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR);
+       std::string tokendir;
+
+       rv = findTokenDirectory(basedir, tokendir, serial, token);
+
+       if (rv)
+       {
+               std::string fulldir = basedir;
+               if (fulldir.find_last_of(OS_PATHSEP) != (fulldir.size()-1))
+               {
+                       fulldir += OS_PATHSEP + tokendir;
+               }
+               else
+               {
+                       fulldir += tokendir;
+               }
+
+               rv = rmdir(fulldir);
+               if (rv)
+               {
+                       printf("The token (%s) has been deleted.\n", fulldir.c_str());
+               }
+       }
+
+       finalizeSoftHSM();
+
+       return rv;
+}
+
+bool initSoftHSM()
+{
+       // Not using threading
+       MutexFactory::i()->disable();
+
+       // Initiate SecureMemoryRegistry
+       if (SecureMemoryRegistry::i() == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not initiate SecureMemoryRegistry.\n");
+               return false;
+       }
+
+       // Build the CryptoFactory
+       if (CryptoFactory::i() == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not initiate CryptoFactory.\n");
+               return false;
+       }
+
+#ifdef WITH_FIPS
+       // Check the FIPS status
+       if (!CryptoFactory::i()->getFipsSelfTestStatus())
+       {
+               fprintf(stderr, "ERROR: FIPS self test failed.\n");
+               return false;
+       }
+#endif
+
+       // Load the configuration
+       if (!Configuration::i()->reload(SimpleConfigLoader::i()))
+       {
+               fprintf(stderr, "ERROR: Could not load the SoftHSM configuration.\n");
+               return false;
+       }
+
+       // Configure the log level
+       if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL)))
+       {
+               fprintf(stderr, "ERROR: Could not configure the log level.\n");
+               return false;
+       }
+
+       // Configure object store storage backend used by all tokens.
+       if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND)))
+       {
+               fprintf(stderr, "ERROR: Could not select token backend.\n");
+               return false;
+       }
+
+       return true;
+}
+
+void finalizeSoftHSM()
+{
+       CryptoFactory::reset();
+       SecureMemoryRegistry::reset();
+}
+
+// Find the token directory
+bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label)
+{
+       if (serial == NULL && label == NULL)
+       {
+               return false;
+       }
+
+       // Load the variables
+       CK_UTF8CHAR paddedSerial[16];
+       CK_UTF8CHAR paddedLabel[32];
+       if (serial != NULL)
+       {
+               size_t inSize = strlen(serial);
+               size_t outSize = sizeof(paddedSerial);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --serial is too long.\n");
+                       return false;
+               }
+               memset(paddedSerial, ' ', outSize);
+               memcpy(paddedSerial, serial, inSize);
+       }
+       if (label != NULL)
+       {
+               size_t inSize = strlen(label);
+               size_t outSize = sizeof(paddedLabel);
+               if (inSize > outSize)
+               {
+                       fprintf(stderr, "ERROR: --token is too long.\n");
+                       return false;
+               }
+               memset(paddedLabel, ' ', outSize);
+               memcpy(paddedLabel, label, inSize);
+       }
+
+       // Find all tokens in the specified path
+       Directory storeDir(basedir);
+
+       if (!storeDir.isValid())
+       {
+               fprintf(stderr, "Failed to enumerate object store in %s\n", basedir.c_str());
+
+               return false;
+       }
+
+       // Assume that all subdirectories are tokens
+       std::vector<std::string> dirs = storeDir.getSubDirs();
+
+       ByteString tokenLabel;
+       ByteString tokenSerial;
+       CK_UTF8CHAR paddedTokenSerial[16];
+       CK_UTF8CHAR paddedTokenLabel[32];
+       size_t counter = 0;
+       for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); i++)
+       {
+               memset(paddedTokenSerial, ' ', sizeof(paddedTokenSerial));
+               memset(paddedTokenLabel, ' ', sizeof(paddedTokenLabel));
+
+               // Create a token instance
+               ObjectStoreToken* token = ObjectStoreToken::accessToken(basedir, *i);
+
+               if (!token->isValid())
+               {
+                       delete token;
+                       continue;
+               }
+
+               if (token->getTokenLabel(tokenLabel) && tokenLabel.size() <= sizeof(paddedTokenLabel))
+               {
+                       strncpy((char*) paddedTokenLabel, (char*) tokenLabel.byte_str(), tokenLabel.size());
+               }
+               if (token->getTokenSerial(tokenSerial) && tokenSerial.size() <= sizeof(paddedTokenSerial))
+               {
+                       strncpy((char*) paddedTokenSerial, (char*) tokenSerial.byte_str(), tokenSerial.size());
+               }
+
+               if (serial != NULL && label == NULL &&
+                       memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0)
+               {
+                       printf("Found token (%s) with matching serial.\n", i->c_str());
+                       tokendir = i->c_str();
+                       counter++;
+               }
+               if (serial == NULL && label != NULL &&
+                       memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0)
+               {
+                       printf("Found token (%s) with matching token label.\n", i->c_str());
+                       tokendir = i->c_str();
+                       counter++;
+               }
+               if (serial != NULL && label != NULL &&
+                       memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0 &&
+                       memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0)
+               {
+                       printf("Found token (%s) with matching serial and token label.\n", i->c_str());
+                       tokendir = i->c_str();
+                       counter++;
+               }
+
+               delete token;
+       }
+
+       if (counter == 1) return true;
+       if (counter > 1)
+       {
+               fprintf(stderr, "ERROR: Found multiple matching tokens.\n");
+               return false;
+       }
+
+       fprintf(stderr, "ERROR: Could not find a token using --serial or --token.\n");
+       return false;
+}
+
+
+// Delete a directory
+bool rmdir(std::string path)
+{
+       bool rv = true;
+
+#ifndef _WIN32
+       // Enumerate the directory
+       DIR* dir = opendir(path.c_str());
+
+       if (dir == NULL)
+       {
+               fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str());
+               return false;
+       }
+
+       // Enumerate the directory
+       struct dirent* entry = NULL;
+
+       while ((entry = readdir(dir)) != NULL)
+       {
+               bool handled = false;
+
+               // Check if this is the . or .. entry
+               if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+               {
+                       continue;
+               }
+
+               // Convert the name of the entry to a C++ string
+               std::string name(entry->d_name);
+               std::string fullPath = path + OS_PATHSEP + name;
+
+#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE)
+               // Determine the type of the entry
+               switch(entry->d_type)
+               {
+                       case DT_DIR:
+                               // This is a directory
+                               rv = rmdir(fullPath);
+                               handled = true;
+                               break;
+                       case DT_REG:
+                               // This is a regular file
+                               rv = rm(fullPath);
+                               handled = true;
+                               break;
+                       default:
+                               break;
+               }
+#endif
+
+               if (rv == false)
+                       break;
+
+               if (!handled)
+               {
+                       // The entry type has to be determined using lstat
+                       struct stat entryStatus;
+
+                       if (!lstat(fullPath.c_str(), &entryStatus))
+                       {
+                               if (S_ISDIR(entryStatus.st_mode))
+                               {
+                                       // This is a directory
+                                       rv = rmdir(fullPath);
+                               }
+                               else if (S_ISREG(entryStatus.st_mode))
+                               {
+                                       // This is a regular file
+                                       rv = rm(fullPath);
+                               }
+                       }
+
+                       if (rv == false)
+                               break;
+               }
+       }
+
+       // Close the directory
+       closedir(dir);
+#else
+       // Enumerate the directory
+       std::string pattern;
+       intptr_t h;
+       struct _finddata_t fi;
+
+       if ((path.back() == '/') || (path.back() == '\\'))
+               pattern = path + "*";
+       else
+               pattern = path + "/*";
+       memset(&fi, 0, sizeof(fi));
+       h = _findfirst(pattern.c_str(), &fi);
+       if (h == -1)
+       {
+               // empty directory
+               if (errno == ENOENT)
+                       goto finished;
+
+               fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str());
+
+               return false;
+       }
+
+       // scan files & subdirs
+       do
+       {
+               // Check if this is the . or .. entry
+               if (!strcmp(fi.name, ".") || !strcmp(fi.name, ".."))
+                       continue;
+
+               std::string fullPath = path + OS_PATHSEP + fi.name;
+               if ((fi.attrib & _A_SUBDIR) == 0)
+               {
+                       // This is a regular file
+                       rv = rm(fullPath);
+               }
+               else
+               {
+                       // This is a directory
+                       rv = rmdir(fullPath);
+               }
+
+               memset(&fi, 0, sizeof(fi));
+
+               if (rv == false)
+                       break;
+       } while (_findnext(h, &fi) == 0);
+
+       (void) _findclose(h);
+
+    finished:
+#endif
+
+       if (rv == false)
+               return false;
+
+       int result;
+#ifndef _WIN32
+       result = ::rmdir(path.c_str());
+#else
+       result = _rmdir(path.c_str());
+#endif
+
+       if (result != 0)
+       {
+               fprintf(stderr, "ERROR: Could not delete the directory: %s\n", path.c_str());
+               return false;
+       }
+
+       return true;
+}
+
+// Delete a file
+bool rm(std::string path)
+{
+       int result;
+
+#ifndef _WIN32
+       result = ::remove(path.c_str());
+#else
+       result = _unlink(path.c_str());
+#endif
+
+       if (result != 0)
+       {
+               fprintf(stderr, "ERROR: Could not delete the file: %s\n", path.c_str());
+               return false;
+       }
+
+       return true;
+}
+
+// Show what slots are available
+int showSlots()
+{
+       CK_ULONG ulSlotCount;
+       CK_RV rv = p11->C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the number of slots.\n");
+               return 1;
+       }
+
+       CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
+       if (!pSlotList)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+               return 1;
+       }
+
+       rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the slot list.\n");
+               free(pSlotList);
+               return 1;
+       }
+
+       printf("Available slots:\n");
+
+       for (CK_ULONG i = 0; i < ulSlotCount; i++)
+       {
+               CK_SLOT_INFO slotInfo;
+               CK_TOKEN_INFO tokenInfo;
+
+               rv = p11->C_GetSlotInfo(pSlotList[i], &slotInfo);
+               if (rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not get info about slot %lu.\n", pSlotList[i]);
+                       continue;
+               }
+
+               printf("Slot %lu\n", pSlotList[i]);
+               printf("    Slot info:\n");
+               printf("        Description:      %.*s\n", 64, slotInfo.slotDescription);
+               printf("        Manufacturer ID:  %.*s\n", 32, slotInfo.manufacturerID);
+               printf("        Hardware version: %i.%i\n", slotInfo.hardwareVersion.major,
+                                                           slotInfo.hardwareVersion.minor);
+               printf("        Firmware version: %i.%i\n", slotInfo.firmwareVersion.major,
+                                                           slotInfo.firmwareVersion.minor);
+               printf("        Token present:    ");
+               if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0)
+               {
+                       printf("no\n");
+                       continue;
+               }
+
+               printf("yes\n");
+               printf("    Token info:\n");
+
+               rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo);
+               if (rv != CKR_OK)
+               {
+                       fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n",
+                               pSlotList[i]);
+                       continue;
+               }
+
+               printf("        Manufacturer ID:  %.*s\n", 32, tokenInfo.manufacturerID);
+               printf("        Model:            %.*s\n", 16, tokenInfo.model);
+               printf("        Hardware version: %i.%i\n", tokenInfo.hardwareVersion.major,
+                                                           tokenInfo.hardwareVersion.minor);
+               printf("        Firmware version: %i.%i\n", tokenInfo.firmwareVersion.major,
+                                                           tokenInfo.firmwareVersion.minor);
+               printf("        Serial number:    %.*s\n", 16, tokenInfo.serialNumber);
+               printf("        Initialized:      ");
+               if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0)
+               {
+                       printf("no\n");
+               }
+               else
+               {
+                       printf("yes\n");
+               }
+
+               printf("        User PIN init.:   ");
+               if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == 0)
+               {
+                       printf("no\n");
+               }
+               else
+               {
+                       printf("yes\n");
+               }
+
+               printf("        Label:            %.*s\n", 32, tokenInfo.label);
+
+       }
+
+       free(pSlotList);
+
+       return 0;
+}
+
+// Import a key pair from given path
+int importKeyPair
+(
+       char* filePath,
+       char* filePIN,
+       CK_SLOT_ID slotID,
+       char* userPIN,
+       char* label,
+       char* objectID,
+       int forceExec,
+       int noPublicKey
+)
+{
+       char user_pin_copy[MAX_PIN_LEN+1];
+
+       if (label == NULL)
+       {
+               fprintf(stderr, "ERROR: A label for the object must be supplied. "
+                               "Use --label <text>\n");
+               return 1;
+       }
+
+       if (objectID == NULL)
+       {
+               fprintf(stderr, "ERROR: An ID for the object must be supplied. "
+                               "Use --id <hex>\n");
+               return 1;
+       }
+
+       size_t objIDLen = 0;
+       char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen);
+       if (objID == NULL)
+       {
+               fprintf(stderr, "Please edit --id <hex> to correct error.\n");
+               return 1;
+       }
+
+       CK_SESSION_HANDLE hSession;
+       CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
+                                       NULL_PTR, NULL_PTR, &hSession);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_SLOT_ID_INVALID)
+               {
+                       fprintf(stderr, "ERROR: The given slot does not exist.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
+               }
+               free(objID);
+               return 1;
+       }
+
+       // Get the password
+       if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
+       {
+               fprintf(stderr, "ERROR: Could not get user PIN\n");
+               free(objID);
+               return 1;
+       }
+
+       rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_PIN_INCORRECT) {
+                       fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not log in on the token.\n");
+               }
+               free(objID);
+               return 1;
+       }
+
+       CK_OBJECT_HANDLE oHandle = searchObject(hSession, objID, objIDLen);
+       if (oHandle != CK_INVALID_HANDLE && forceExec == 0)
+       {
+               free(objID);
+               fprintf(stderr, "ERROR: The ID is already assigned to another object. "
+                               "Use --force to override this message.\n");
+               return 1;
+       }
+
+       crypto_init();
+       int result = crypto_import_key_pair(hSession, filePath, filePIN, label, objID, objIDLen, noPublicKey);
+       crypto_final();
+
+       free(objID);
+
+       return result;
+}
+
+// Import a secret key from given path
+int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID)
+{
+       char user_pin_copy[MAX_PIN_LEN+1];
+
+       if (label == NULL)
+       {
+               fprintf(stderr, "ERROR: A label for the object must be supplied. "
+                               "Use --label <text>\n");
+               return 1;
+       }
+
+       if (objectID == NULL)
+       {
+               fprintf(stderr, "ERROR: An ID for the object must be supplied. "
+                               "Use --id <hex>\n");
+               return 1;
+       }
+
+       size_t objIDLen = 0;
+       char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen);
+       if (objID == NULL)
+       {
+               fprintf(stderr, "Please edit --id <hex> to correct error.\n");
+               return 1;
+       }
+
+       // Get the password
+       if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
+       {
+               fprintf(stderr, "ERROR: Could not get user PIN\n");
+               return 1;
+       }
+
+       CK_SESSION_HANDLE hSession;
+       CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
+                                       NULL_PTR, NULL_PTR, &hSession);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_SLOT_ID_INVALID)
+               {
+                       fprintf(stderr, "ERROR: The given slot does not exist.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
+               }
+               return 1;
+       }
+
+       rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_PIN_INCORRECT) {
+                       fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
+               }
+               else
+               {
+                       fprintf(stderr, "ERROR: Could not log in on the token.\n");
+               }
+               return 1;
+       }
+
+       crypto_init();
+       int result = crypto_import_aes_key(hSession, filePath, label, objID, objIDLen);
+       crypto_final();
+
+       return result;
+}
+
+// Convert a char array of hexadecimal characters into a binary representation
+char* hexStrToBin(char* objectID, int idLength, size_t* newLen)
+{
+       char* bytes = NULL;
+
+       if (idLength < 2 || idLength % 2 != 0)
+       {
+               fprintf(stderr, "ERROR: Invalid length on hex string.\n");
+               return NULL;
+       }
+
+       for (int i = 0; i < idLength; i++)
+       {
+               if (hexdigit_to_int(objectID[i]) == -1)
+               {
+                       fprintf(stderr, "ERROR: Invalid character in hex string.\n");
+                       return NULL;
+               }
+       }
+
+       *newLen = idLength / 2;
+       bytes = (char*) malloc(*newLen);
+       if (bytes == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+               return NULL;
+       }
+
+       for (size_t i = 0; i < *newLen; i++)
+       {
+               bytes[i] = hexdigit_to_int(objectID[2*i]) * 16 +
+                               hexdigit_to_int(objectID[2*i+1]);
+       }
+
+       return bytes;
+}
+
+// Return the integer value of a hexadecimal character
+int hexdigit_to_int(char ch)
+{
+       switch (ch)
+       {
+               case '0':
+                       return 0;
+               case '1':
+                       return 1;
+               case '2':
+                       return 2;
+               case '3':
+                       return 3;
+               case '4':
+                       return 4;
+               case '5':
+                       return 5;
+               case '6':
+                       return 6;
+               case '7':
+                       return 7;
+               case '8':
+                       return 8;
+               case '9':
+                       return 9;
+               case 'a':
+               case 'A':
+                       return 10;
+               case 'b':
+               case 'B':
+                       return 11;
+               case 'c':
+               case 'C':
+                       return 12;
+               case 'd':
+               case 'D':
+                       return 13;
+               case 'e':
+               case 'E':
+                       return 14;
+               case 'f':
+               case 'F':
+                       return 15;
+               default:
+                       return -1;
+       }
+}
+
+// Search for an object
+CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen)
+{
+       if (objID == NULL)
+       {
+               return CK_INVALID_HANDLE;
+       }
+
+       CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+       CK_ULONG objectCount = 0;
+
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &oClass, sizeof(oClass) },
+               { CKA_ID,    objID,   objIDLen }
+       };
+
+       CK_RV rv = p11->C_FindObjectsInit(hSession, objTemplate, 2);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not prepare the object search.\n");
+               return CK_INVALID_HANDLE;
+       }
+
+       rv = p11->C_FindObjects(hSession, &hObject, 1, &objectCount);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not get the search results.\n");
+               return CK_INVALID_HANDLE;
+       }
+
+       rv = p11->C_FindObjectsFinal(hSession);
+       if (rv != CKR_OK)
+       {
+               fprintf(stderr, "ERROR: Could not finalize the search.\n");
+               return CK_INVALID_HANDLE;
+       }
+
+       if (objectCount == 0)
+       {
+               return CK_INVALID_HANDLE;
+       }
+
+       return hObject;
+}
diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.h b/SoftHSMv2/src/bin/util/softhsm2-util.h
new file mode 100644 (file)
index 0000000..3c49314
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ softhsm2-util.h
+
+ This program can be used for interacting with HSMs using PKCS#11.
+ The default library is the libsofthsm2.so
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_H
+#define _SOFTHSM_V2_SOFTHSM2_UTIL_H
+
+#include "cryptoki.h"
+#include <string>
+
+// Main functions
+
+void usage();
+bool checkSetup();
+int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN);
+bool deleteToken(char* serial, char* token);
+bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label);
+bool rmdir(std::string path);
+bool rm(std::string path);
+int showSlots();
+int importKeyPair(char* filePath, char* filePIN, CK_SLOT_ID slotID, char* userPIN, char* objectLabel, char* objectID, int forceExec, int noPublicKey);
+int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID);
+int crypto_import_key_pair(CK_SESSION_HANDLE hSession, char* filePath, char* filePIN, char* label, char* objID, size_t objIDLen, int noPublicKey);
+int crypto_import_aes_key(CK_SESSION_HANDLE hSession, char* filePath, char* label, char* objID, size_t objIDLen);
+
+// Support functions
+
+void crypto_init();
+void crypto_final();
+
+/// SoftHSM internal funtions
+bool initSoftHSM();
+void finalizeSoftHSM();
+
+/// Hex
+char* hexStrToBin(char* objectID, int idLength, size_t* newLen);
+int hexdigit_to_int(char ch);
+
+/// Library
+#if !defined(UTIL_BOTAN) && !defined(UTIL_OSSL)
+static void* moduleHandle;
+#endif
+extern CK_FUNCTION_LIST_PTR p11;
+
+/// PKCS#11 support
+CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen);
+
+#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_H
diff --git a/SoftHSMv2/src/bin/win32/getopt.cpp b/SoftHSMv2/src/bin/win32/getopt.cpp
new file mode 100644 (file)
index 0000000..dfeabe2
--- /dev/null
@@ -0,0 +1,520 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <config.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+
+/* Windows needs warnx().  We change the definition though:
+ *  1. (another) global is defined, opterrmsg, which holds the error message
+ *  2. errors are always printed out on stderr w/o the program name
+ * Note that opterrmsg always gets set no matter what opterr is set to.  The
+ * error message will not be printed if opterr is 0 as usual.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+extern char opterrmsg[128];
+char opterrmsg[128]; /* last error message is stored here */
+
+static void warnx(int print_error, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       if (fmt != NULL)
+               _vsnprintf(opterrmsg, 128, fmt, ap);
+       else
+               opterrmsg[0]='\0';
+       va_end(ap);
+       if (print_error) {
+               fprintf(stderr, opterrmsg);
+               fprintf(stderr, "\n");
+       }
+}
+
+#endif /*_WIN32*/
+
+/* not part of the original file */
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(X)
+#endif
+
+#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
+#define REPLACE_GETOPT
+#endif
+
+int    opterr = 1;             /* if error message should be printed */
+int    optind = 1;             /* index into parent argv vector */
+int    optopt = '?';           /* character checked for validity */
+int    optreset;               /* reset getopt */
+char    *optarg;               /* argument associated with option */
+
+#if !HAVE_GETOPT_LONG
+#define IGNORE_FIRST   (*options == '-' || *options == '+')
+#define PRINT_ERROR    ((opterr) && ((*options != ':') \
+                                     || (IGNORE_FIRST && options[1] != ':')))
+#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
+#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
+/* XXX: GNU ignores PC if *options == '-' */
+#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
+
+/* return values */
+#define        BADCH   (int)'?'
+#define        BADARG          ((IGNORE_FIRST && options[1] == ':') \
+                        || (*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define        EMSG    ""
+
+static int getopt_internal(int, char * const *, const char *);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+       int c;
+
+       c = a % b;
+       while (c != 0) {
+               a = b;
+               b = c;
+               c = a % b;
+       }
+          
+       return b;
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end,
+            int opt_end, char * const *nargv)
+{
+       int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+       char *swap;
+
+       _DIAGASSERT(nargv != NULL);
+
+       /*
+        * compute lengths of blocks and number and size of cycles
+        */
+       nnonopts = panonopt_end - panonopt_start;
+       nopts = opt_end - panonopt_end;
+       ncycle = gcd(nnonopts, nopts);
+       cyclelen = (opt_end - panonopt_start) / ncycle;
+
+       for (i = 0; i < ncycle; i++) {
+               cstart = panonopt_end+i;
+               pos = cstart;
+               for (j = 0; j < cyclelen; j++) {
+                       if (pos >= panonopt_end)
+                               pos -= nnonopts;
+                       else
+                               pos += nopts;
+                       swap = nargv[pos];
+                       /* LINTED const cast */
+                       ((char **) nargv)[pos] = nargv[cstart];
+                       /* LINTED const cast */
+                       ((char **)nargv)[cstart] = swap;
+               }
+       }
+}
+
+/*
+ * getopt_internal --
+ *     Parse argc/argv argument vector.  Called by user level routines.
+ *  Returns -2 if -- is found (can be long option or end of options marker).
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options)
+{
+       char *oli;                              /* option letter list index */
+       int optchar;
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+
+       optarg = NULL;
+
+       /*
+        * XXX Some programs (like rsyncd) expect to be able to
+        * XXX re-initialize optind to 0 and have getopt_long(3)
+        * XXX properly function again.  Work around this braindamage.
+        */
+       if (optind == 0)
+               optind = 1;
+
+       if (optreset)
+               nonopt_start = nonopt_end = -1;
+start:
+       if (optreset || !*place) {              /* update scanning pointer */
+               optreset = 0;
+               if (optind >= nargc) {          /* end of argument vector */
+                       place = EMSG;
+                       if (nonopt_end != -1) {
+                               /* do permutation, if we have to */
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, nargv);
+                               optind -= nonopt_end - nonopt_start;
+                       }
+                       else if (nonopt_start != -1) {
+                               /*
+                                * If we skipped non-options, set optind
+                                * to the first of them.
+                                */
+                               optind = nonopt_start;
+                       }
+                       nonopt_start = nonopt_end = -1;
+                       return -1;
+               }
+               if ((*(place = nargv[optind]) != '-')
+                   || (place[1] == '\0')) {    /* found non-option */
+                       place = EMSG;
+                       if (IN_ORDER) {
+                               /*
+                                * GNU extension: 
+                                * return non-option as argument to option 1
+                                */
+                               optarg = nargv[optind++];
+                               return INORDER;
+                       }
+                       if (!PERMUTE) {
+                               /*
+                                * if no permutation wanted, stop parsing
+                                * at first non-option
+                                */
+                               return -1;
+                       }
+                       /* do permutation */
+                       if (nonopt_start == -1)
+                               nonopt_start = optind;
+                       else if (nonopt_end != -1) {
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, nargv);
+                               nonopt_start = optind -
+                                   (nonopt_end - nonopt_start);
+                               nonopt_end = -1;
+                       }
+                       optind++;
+                       /* process next argument */
+                       goto start;
+               }
+               if (nonopt_start != -1 && nonopt_end == -1)
+                       nonopt_end = optind;
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       place++;
+                       return -2;
+               }
+       }
+       if ((optchar = (int)*place++) == (int)':' ||
+           (oli = (char *) strchr(options + (IGNORE_FIRST ? 1 : 0),
+                                  optchar)) == NULL) {
+               /* option letter unknown or ':' */
+               if (!*place)
+                       ++optind;
+#ifndef _WIN32
+               if (PRINT_ERROR)
+                       warnx(illoptchar, optchar);
+#else
+                       warnx(PRINT_ERROR, illoptchar, optchar);
+#endif
+               optopt = optchar;
+               return BADCH;
+       }
+       if (optchar == 'W' && oli[1] == ';') {          /* -W long-option */
+               /* XXX: what if no long options provided (called by getopt)? */
+               if (*place) 
+                       return -2;
+
+               if (++optind >= nargc) {        /* no arg */
+                       place = EMSG;
+#ifndef _WIN32
+                       if (PRINT_ERROR)
+                               warnx(recargchar, optchar);
+#else
+                               warnx(PRINT_ERROR, recargchar, optchar);
+#endif
+                       optopt = optchar;
+                       return BADARG;
+               } else                          /* white space */
+                       place = nargv[optind];
+               /*
+                * Handle -W arg the same as --arg (which causes getopt to
+                * stop parsing).
+                */
+               return -2;
+       }
+       if (*++oli != ':') {                    /* doesn't take argument */
+               if (!*place)
+                       ++optind;
+       } else {                                /* takes (optional) argument */
+               optarg = NULL;
+               if (*place)                     /* no white space */
+                       optarg = place;
+               /* XXX: disable test for :: if PC? (GNU doesn't) */
+               else if (oli[1] != ':') {       /* arg not optional */
+                       if (++optind >= nargc) {        /* no arg */
+                               place = EMSG;
+#ifndef _WIN32
+                               if (PRINT_ERROR)
+                                       warnx(recargchar, optchar);
+#else
+                                       warnx(PRINT_ERROR, recargchar, optchar);
+#endif
+                               optopt = optchar;
+                               return BADARG;
+                       } else
+                               optarg = nargv[optind];
+               }
+               place = EMSG;
+               ++optind;
+       }
+       /* dump back option letter */
+       return optchar;
+}
+
+/*
+ * getopt --
+ *     Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the real getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+       int retval;
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+
+       if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+               ++optind;
+               /*
+                * We found an option (--), so if we skipped non-options,
+                * we have to permute.
+                */
+               if (nonopt_end != -1) {
+                       permute_args(nonopt_start, nonopt_end, optind,
+                                      nargv);
+                       optind -= nonopt_end - nonopt_start;
+               }
+               nonopt_start = nonopt_end = -1;
+               retval = -1;
+       }
+       return retval;
+}
+
+/*
+ * getopt_long --
+ *     Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc,
+           char * const *nargv,
+           const char *options,
+           const struct option *long_options,
+           int *idx)
+{
+       int retval;
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+       _DIAGASSERT(long_options != NULL);
+       /* idx may be NULL */
+
+       if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+               char *current_argv, *has_equal;
+               size_t current_argv_len;
+               int i, match;
+
+               current_argv = place;
+               match = -1;
+
+               optind++;
+               place = EMSG;
+
+               if (*current_argv == '\0') {            /* found "--" */
+                       /*
+                        * We found an option (--), so if we skipped
+                        * non-options, we have to permute.
+                        */
+                       if (nonopt_end != -1) {
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, nargv);
+                               optind -= nonopt_end - nonopt_start;
+                       }
+                       nonopt_start = nonopt_end = -1;
+                       return -1;
+               }
+               if ((has_equal = strchr(current_argv, '=')) != NULL) {
+                       /* argument found (--option=arg) */
+                       current_argv_len = has_equal - current_argv;
+                       has_equal++;
+               } else
+                       current_argv_len = strlen(current_argv);
+           
+               for (i = 0; long_options[i].name; i++) {
+                       /* find matching long option */
+                       if (strncmp(current_argv, long_options[i].name,
+                           current_argv_len))
+                               continue;
+
+                       if (strlen(long_options[i].name) ==
+                           (unsigned)current_argv_len) {
+                               /* exact match */
+                               match = i;
+                               break;
+                       }
+                       if (match == -1)                /* partial match */
+                               match = i;
+                       else {
+                               /* ambiguous abbreviation */
+#ifndef _WIN32
+                               if (PRINT_ERROR)
+                                       warnx(ambig, (int)current_argv_len,
+                                            current_argv);
+#else
+                                       warnx(PRINT_ERROR, ambig, (int)current_argv_len,
+                                            current_argv);
+#endif
+                               optopt = 0;
+                               return BADCH;
+                       }
+               }
+               if (match != -1) {                      /* option found */
+                       if (long_options[match].has_arg == no_argument
+                           && has_equal) {
+#ifndef _WIN32
+                               if (PRINT_ERROR)
+                                       warnx(noarg, (int)current_argv_len,
+                                            current_argv);
+#else
+                                       warnx(PRINT_ERROR, noarg, (int)current_argv_len,
+                                            current_argv);
+#endif
+                               /*
+                                * XXX: GNU sets optopt to val regardless of
+                                * flag
+                                */
+                               if (long_options[match].flag == NULL)
+                                       optopt = long_options[match].val;
+                               else
+                                       optopt = 0;
+                               return BADARG;
+                       }
+                       if (long_options[match].has_arg == required_argument ||
+                           long_options[match].has_arg == optional_argument) {
+                               if (has_equal)
+                                       optarg = has_equal;
+                               else if (long_options[match].has_arg ==
+                                   required_argument) {
+                                       /*
+                                        * optional argument doesn't use
+                                        * next nargv
+                                        */
+                                       optarg = nargv[optind++];
+                               }
+                       }
+                       if ((long_options[match].has_arg == required_argument)
+                           && (optarg == NULL)) {
+                               /*
+                                * Missing argument; leading ':'
+                                * indicates no error should be generated
+                                */
+#ifndef _WIN32
+                               if (PRINT_ERROR)
+                                       warnx(recargstring, current_argv);
+#else
+                                       warnx(PRINT_ERROR, recargstring, current_argv);
+#endif
+                               /*
+                                * XXX: GNU sets optopt to val regardless
+                                * of flag
+                                */
+                               if (long_options[match].flag == NULL)
+                                       optopt = long_options[match].val;
+                               else
+                                       optopt = 0;
+                               --optind;
+                               return BADARG;
+                       }
+               } else {                        /* unknown option */
+#ifndef _WIN32
+                       if (PRINT_ERROR)
+                               warnx(illoptstring, current_argv);
+#else
+                               warnx(PRINT_ERROR, illoptstring, current_argv);
+#endif
+                       optopt = 0;
+                       return BADCH;
+               }
+               if (long_options[match].flag) {
+                       *long_options[match].flag = long_options[match].val;
+                       retval = 0;
+               } else 
+                       retval = long_options[match].val;
+               if (idx)
+                       *idx = match;
+       }
+       return retval;
+}
+#endif /* !GETOPT_LONG */
diff --git a/SoftHSMv2/src/bin/win32/getopt.h b/SoftHSMv2/src/bin/win32/getopt.h
new file mode 100644 (file)
index 0000000..f6b65a5
--- /dev/null
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+#ifdef _WIN32
+/* from <sys/cdefs.h> */
+# ifdef  __cplusplus
+#  define __BEGIN_DECLS  extern "C" {
+#  define __END_DECLS    }
+# else
+#  define __BEGIN_DECLS
+#  define __END_DECLS
+# endif
+# define __P(args)      args
+#endif
+
+/*#ifndef _WIN32
+#include <sys/cdefs.h>
+#include <unistd.h>
+#endif*/
+
+/*
+ * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
+ */
+#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
+#define no_argument        0
+#define required_argument  1
+#define optional_argument  2
+
+struct option {
+        /* name of long option */
+        const char *name;
+        /*
+         * one of no_argument, required_argument, and optional_argument:
+         * whether option takes an argument
+         */
+        int has_arg;
+        /* if not NULL, set *flag to val when option found */
+        int *flag;
+        /* if flag not NULL, value to set *flag to; else return value */
+        int val;
+};
+
+__BEGIN_DECLS
+int getopt_long __P((int, char * const *, const char *,
+    const struct option *, int *));
+__END_DECLS
+#endif
+
+#ifdef _WIN32
+/* These are global getopt variables */
+__BEGIN_DECLS
+
+extern int   opterr,   /* if error message should be printed */
+             optind,   /* index into parent argv vector */
+             optopt,   /* character checked for validity */
+             optreset; /* reset getopt */
+extern char* optarg;   /* argument associated with option */
+
+/* Original getopt */
+int getopt __P((int, char * const *, const char *));
+
+__END_DECLS
+#endif
+#endif /* !_GETOPT_H_ */
diff --git a/SoftHSMv2/src/bin/win32/getpassphase.cpp b/SoftHSMv2/src/bin/win32/getpassphase.cpp
new file mode 100644 (file)
index 0000000..9d8aaca
--- /dev/null
@@ -0,0 +1,35 @@
+/* WIN32 getpassphrase */
+
+#include <config.h>
+#include <stdio.h>
+
+char *
+getpassphrase(const char *prompt) {
+       static char buf[128];
+       HANDLE h;
+       DWORD cc, mode;
+       int cnt;
+
+       h = GetStdHandle(STD_INPUT_HANDLE);
+       fputs(prompt, stderr);
+       fflush(stderr);
+       fflush(stdout);
+       FlushConsoleInputBuffer(h);
+       GetConsoleMode(h, &mode);
+       SetConsoleMode(h, ENABLE_PROCESSED_INPUT);
+
+       for (cnt = 0; cnt < sizeof(buf) - 1; cnt++)
+       {
+               ReadFile(h, buf + cnt, 1, &cc, NULL);
+               if (buf[cnt] == '\r')
+                       break;
+               fputc('*', stdout);
+               fflush(stderr);
+               fflush(stdout);
+       }
+
+       SetConsoleMode(h, mode);
+       buf[cnt] = '\0';
+       fputs("\n", stderr);
+       return (buf);
+}
diff --git a/SoftHSMv2/src/lib/Makefile.am b/SoftHSMv2/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..f3f5bb4
--- /dev/null
@@ -0,0 +1,52 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/common \
+                               -I$(srcdir)/crypto \
+                               -I$(srcdir)/data_mgr \
+                               -I$(srcdir)/handle_mgr \
+                               -I$(srcdir)/object_store \
+                               -I$(srcdir)/pkcs11 \
+                               -I$(srcdir)/session_mgr \
+                               -I$(srcdir)/slot_mgr \
+                               @CRYPTO_INCLUDES@
+
+lib_LTLIBRARIES =              libsofthsm2.la
+
+libsofthsm2_la_SOURCES =       access.cpp \
+                               main.cpp \
+                               P11Attributes.cpp \
+                               P11Objects.cpp \
+                               SoftHSM.cpp
+libsofthsm2_la_LIBADD =                common/libsofthsm_common.la \
+                               crypto/libsofthsm_crypto.la \
+                               data_mgr/libsofthsm_datamgr.la \
+                               handle_mgr/libsofthsm_handlemgr.la \
+                               object_store/libsofthsm_objectstore.la \
+                               session_mgr/libsofthsm_sessionmgr.la \
+                               slot_mgr/libsofthsm_slotmgr.la
+libsofthsm2_la_LDFLAGS =       -version-info @VERSION_INFO@ \
+                               -avoid-version -module
+
+# Create a convenience library from all the other convenience library; this is
+# necessary to resolve circular dependencies when statically linking the test
+# executables
+noinst_LTLIBRARIES =           libsofthsm_convarch.la
+
+libsofthsm_convarch_la_SOURCES =
+
+libsofthsm_convarch_la_LIBADD =        $(libsofthsm2_la_LIBADD)
+
+SUBDIRS =                      common \
+                               crypto \
+                               data_mgr \
+                               object_store \
+                               session_mgr \
+                               slot_mgr \
+                               handle_mgr \
+                               test
+
+EXTRA_DIST =                   $(srcdir)/*.h \
+                               $(srcdir)/pkcs11/*.h \
+                               $(srcdir)/win32/*.cc \
+                               $(srcdir)/win32/*.cpp \
+                               $(srcdir)/win32/*.h
diff --git a/SoftHSMv2/src/lib/P11Attributes.cpp b/SoftHSMv2/src/lib/P11Attributes.cpp
new file mode 100644 (file)
index 0000000..28d0f9b
--- /dev/null
@@ -0,0 +1,2514 @@
+/*
+ * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ P11Attributes.h
+
+ This file contains classes for controlling attributes
+ *****************************************************************************/
+
+#include "config.h"
+#include "P11Attributes.h"
+#include "ByteString.h"
+#include "CryptoFactory.h"
+#include "DESKey.h"
+#include "AESKey.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+// Constructor
+P11Attribute::P11Attribute(OSObject* inobject)
+{
+       osobject = inobject;
+       type = CKA_VENDOR_DEFINED;
+       size = (CK_ULONG)-1;
+       checks = 0;
+}
+
+// Destructor
+P11Attribute::~P11Attribute()
+{
+}
+
+CK_RV P11Attribute::updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       ByteString value;
+       if (isPrivate)
+       {
+               if (!token->encrypt(ByteString((unsigned char*)pValue, ulValueLen),value))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+               value = ByteString((unsigned char*)pValue, ulValueLen);
+       if (value.size() < ulValueLen)
+               return CKR_GENERAL_ERROR;
+       osobject->setAttribute(type, value);
+       return CKR_OK;
+}
+
+bool P11Attribute::isModifiable()
+{
+       // Get the CKA_MODIFIABLE attribute, when the attribute is
+       // not present return the default value which is CK_TRUE.
+       if (!osobject->attributeExists(CKA_MODIFIABLE)) return true;
+
+       return osobject->getBooleanValue(CKA_MODIFIABLE, true);
+}
+
+bool P11Attribute::isSensitive()
+{
+       // Get the CKA_SENSITIVE attribute, when the attribute is not present
+       // assume the object is not sensitive.
+       if (!osobject->attributeExists(CKA_SENSITIVE)) return false;
+
+       return osobject->getBooleanValue(CKA_SENSITIVE, false);
+}
+
+bool P11Attribute::isExtractable()
+{
+       // Get the CKA_EXTRACTABLE attribute, when the attribute is
+       // not present assume the object allows extraction.
+       if (!osobject->attributeExists(CKA_EXTRACTABLE)) return true;
+
+       return osobject->getBooleanValue(CKA_EXTRACTABLE, true);
+}
+
+bool P11Attribute::isTrusted()
+{
+       // Get the CKA_TRUSTED attribute, when the attribute is
+       // not present assume the object is not trusted.
+       if (!osobject->attributeExists(CKA_TRUSTED)) return false;
+
+       return osobject->getBooleanValue(CKA_TRUSTED, false);
+}
+
+// Initialize the attribute
+bool P11Attribute::init()
+{
+       if (osobject == NULL) return false;
+
+       // Create a default value if the attribute does not exist
+       if (osobject->attributeExists(type) == false)
+       {
+               return setDefault();
+       }
+
+       return true;
+}
+
+// Return the attribute type
+CK_ATTRIBUTE_TYPE P11Attribute::getType()
+{
+       return type;
+}
+
+// Return the attribute checks
+CK_ATTRIBUTE_TYPE P11Attribute::getChecks()
+{
+       return checks;
+}
+
+// Retrieve a template map
+static CK_RV retrieveAttributeMap(CK_ATTRIBUTE_PTR pTemplate, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map)
+{
+       size_t nullcnt = 0;
+
+       for (size_t i = 0; i < map.size(); ++i)
+       {
+               if (pTemplate[i].pValue == NULL_PTR)
+                       ++nullcnt;
+       }
+
+       // Caller wants type & size
+       if (nullcnt == map.size())
+       {
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator a = map.begin();
+               for (size_t i = 0; i < map.size(); ++i, ++a)
+               {
+                       pTemplate[i].type = a->first;
+                       const OSAttribute& attr = a->second;
+                       if (attr.isBooleanAttribute())
+                       {
+                               pTemplate[i].ulValueLen = sizeof(CK_BBOOL);
+                       }
+                       else if (attr.isUnsignedLongAttribute())
+                       {
+                               pTemplate[i].ulValueLen = sizeof(CK_ULONG);
+                       }
+                       else if (attr.isByteStringAttribute())
+                       {
+                               pTemplate[i].ulValueLen = attr.getByteStringValue().size();
+                       }
+                       else
+                       {
+                               // Impossible
+                               ERROR_MSG("Internal error: bad attribute in attribute map");
+
+                               return CKR_GENERAL_ERROR;
+                       }
+               }
+
+               return CKR_OK;
+       }
+
+       // Callers wants to get values
+       for (size_t i = 0; i < map.size(); ++i)
+       {
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator a = map.find(pTemplate[i].type);
+               if (a == map.end())
+               {
+                       pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION;
+                       return CKR_ATTRIBUTE_TYPE_INVALID;
+               }
+               const OSAttribute& attr = a->second;
+               if (attr.isBooleanAttribute())
+               {
+                       if (pTemplate[i].ulValueLen < sizeof(CK_BBOOL))
+                       {
+                               pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION;
+                               return CKR_BUFFER_TOO_SMALL;
+                       }
+                       pTemplate[i].ulValueLen = sizeof(CK_BBOOL);
+                       *(CK_BBOOL*)pTemplate[i].pValue = attr.getBooleanValue() ? CK_TRUE : CK_FALSE;
+               }
+               else if (attr.isUnsignedLongAttribute())
+               {
+                       if (pTemplate[i].ulValueLen < sizeof(CK_ULONG))
+                       {
+                               pTemplate[i].ulValueLen= CK_UNAVAILABLE_INFORMATION;
+                               return CKR_BUFFER_TOO_SMALL;
+                       }
+                       pTemplate[i].ulValueLen = sizeof(CK_ULONG);
+                       *(CK_ULONG_PTR)pTemplate[i].pValue= attr.getUnsignedLongValue();
+               }
+               else if (attr.isByteStringAttribute())
+               {
+                       ByteString value = attr.getByteStringValue();
+                       if (pTemplate[i].ulValueLen < value.size())
+                       {
+                               pTemplate[i].ulValueLen= CK_UNAVAILABLE_INFORMATION;
+                               return CKR_BUFFER_TOO_SMALL;
+                       }
+                       pTemplate[i].ulValueLen = value.size();
+                       memcpy(pTemplate[i].pValue, value.const_byte_str(), value.size());
+               }
+               else
+               {
+                       // Impossible
+                       ERROR_MSG("Internal error: bad attribute in attribute map");
+
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+
+       return CKR_OK;
+}
+
+// Retrieve the value if allowed
+CK_RV P11Attribute::retrieve(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG_PTR pulValueLen)
+{
+
+       if (osobject == NULL) {
+               ERROR_MSG("Internal error: osobject field contains NULL_PTR");
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (pulValueLen == NULL) {
+               ERROR_MSG("Internal error: pulValueLen contains NULL_PTR");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // [PKCS#11 v2.40, C_GetAttributeValue]
+       // 1. If the specified attribute (i.e., the attribute specified by the
+       //    type field) for the object cannot be revealed because the object
+       //    is sensitive or unextractable, then the ulValueLen field in that
+       //    triple is modified to hold the value CK_UNAVAILABLE_INFORMATION.
+       //
+       // [PKCS#11 v2.40, 4.2 Common attributes, table 10]
+       //  7  Cannot be revealed if object has its CKA_SENSITIVE attribute
+       //     set to CK_TRUE or its CKA_EXTRACTABLE attribute set to CK_FALSE.
+       if ((checks & ck7) == ck7 && (isSensitive() || !isExtractable())) {
+               *pulValueLen = CK_UNAVAILABLE_INFORMATION;
+               return CKR_ATTRIBUTE_SENSITIVE;
+       }
+
+       // Retrieve the lower level attribute.
+       if (!osobject->attributeExists(type)) {
+               // Should be impossible.
+               ERROR_MSG("Internal error: attribute not present");
+               return CKR_GENERAL_ERROR;
+       }
+       OSAttribute attr = osobject->getAttribute(type);
+
+       // Get the actual attribute size.
+       CK_ULONG attrSize = size;
+       if (size == (CK_ULONG)-1)
+       {
+               // We don't have a fixed size attribute so we need to consult
+               // the lower level attribute for the exact size.
+
+               // Lower level attribute has to be variable sized.
+               if (attr.isByteStringAttribute())
+               {
+                       if (isPrivate && attr.getByteStringValue().size() != 0)
+                       {
+                               ByteString value;
+                               if (!token->decrypt(attr.getByteStringValue(),value))
+                               {
+                                       ERROR_MSG("Internal error: failed to decrypt private attribute value");
+                                       return CKR_GENERAL_ERROR;
+                               }
+                               attrSize = value.size();
+                       }
+                       else
+                               attrSize = attr.getByteStringValue().size();
+               }
+               else if (attr.isMechanismTypeSetAttribute())
+               {
+                       attrSize = attr.getMechanismTypeSetValue().size() * sizeof(CK_MECHANISM_TYPE);
+               }
+               else if (attr.isAttributeMapAttribute())
+               {
+                       attrSize = attr.getAttributeMapValue().size() * sizeof(CK_ATTRIBUTE);
+               }
+               else
+               {
+                       // Should be impossible.
+                       ERROR_MSG("Internal error: attribute has fixed size");
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+
+       // [PKCS#11 v2.40, C_GetAttributeValue]
+       // 3. Otherwise, if the pValue field has the value NULL_PTR, then the
+       //    ulValueLen field is modified to hold the exact length of the
+       //    specified attribute for the object.
+       if (pValue == NULL_PTR) {
+               // Return the size of the attribute.
+               *pulValueLen = attrSize;
+               return CKR_OK;
+       }
+
+       // [PKCS#11 v2.40, C_GetAttributeValue]
+       // 4. Otherwise, if the length specified in ulValueLen is large enough
+       //    to hold the value of the specified attribute for the object, then
+       //    that attribute is copied into the buffer located at pValue, and
+       //    the ulValueLen field is modified to hold the exact length of the
+       //    attribute.
+       if (*pulValueLen >= attrSize)
+       {
+               // Only copy when there is actually something to copy
+               CK_RV rv = CKR_OK;
+
+               if (attr.isUnsignedLongAttribute()) {
+                       *(CK_ULONG_PTR)pValue = attr.getUnsignedLongValue();
+               }
+               else if (attr.isBooleanAttribute())
+               {
+                       *(CK_BBOOL*)pValue = attr.getBooleanValue() ? CK_TRUE : CK_FALSE;
+               }
+               else if (attr.isByteStringAttribute())
+               {
+                       if (isPrivate && attr.getByteStringValue().size() != 0)
+                       {
+                               ByteString value;
+                               if (!token->decrypt(attr.getByteStringValue(),value))
+                               {
+                                       ERROR_MSG("Internal error: failed to decrypt private attribute value");
+                                       return CKR_GENERAL_ERROR;
+                               }
+                               const unsigned char* attrPtr = value.const_byte_str();
+                               memcpy(pValue,attrPtr,attrSize);
+                       }
+                       else if (attr.getByteStringValue().size() != 0)
+                       {
+                               const unsigned char* attrPtr = attr.getByteStringValue().const_byte_str();
+                               memcpy(pValue,attrPtr,attrSize);
+                       }
+               }
+               else if (attr.isMechanismTypeSetAttribute())
+               {
+                       CK_MECHANISM_TYPE_PTR pTemplate = (CK_MECHANISM_TYPE_PTR) pValue;
+                       size_t i = 0;
+
+                       std::set<CK_MECHANISM_TYPE> set = attr.getMechanismTypeSetValue();
+                       for (std::set<CK_MECHANISM_TYPE>::const_iterator it = set.begin(); it != set.end(); ++it)
+                               pTemplate[++i] = *it;
+               }
+               else
+               {
+                       // attr is already retrieved and verified to be an Attribute Map
+                       rv = retrieveAttributeMap((CK_ATTRIBUTE_PTR)pValue, attr.getAttributeMapValue());
+               }
+               *pulValueLen = attrSize;
+               return rv;
+       }
+
+       // [PKCS#11 v2.40, C_GetAttributeValue]
+       // 5. Otherwise, the ulValueLen field is modified to hold the value CK_UNAVAILABLE_INFORMATION.
+       *pulValueLen = CK_UNAVAILABLE_INFORMATION;
+       return CKR_BUFFER_TOO_SMALL;
+}
+
+// Update the value if allowed
+CK_RV P11Attribute::update(Token* token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       if (osobject == NULL) {
+               ERROR_MSG("Internal error: osobject field contains NULL_PTR");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // [PKCS#11 v2.40, 4.1.1 Creating objects]
+       //    2. If the supplied template specifies an invalid value for a valid attribute, then the
+       //    attempt should fail with the error code CKR_ATTRIBUTE_VALUE_INVALID.
+       //    The valid values for Cryptoki attributes are described in the Cryptoki specification.
+
+       // Check for null pointers in values.
+       if (pValue == NULL_PTR && ulValueLen != 0) {
+               ERROR_MSG("The attribute is a NULL_PTR but has a non-zero length")
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // For fixed sized attributes check that the size matches.
+       if (size != ((CK_ULONG)-1) && size != ulValueLen) {
+               ERROR_MSG("The attribute size is different from the expected size")
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // [PKCS#11 v2.40, 4.1.1 Creating objects] OBJECT_OP_CREATE | OBJECT_OP_SET | OBJECT_OP_COPY
+       //    3. If the supplied template specifies a value for a read-only attribute, then the attempt
+       //    should fail with the error code CKR_ATTRIBUTE_READ_ONLY.
+       //    Whether or not a given Cryptoki attribute is read-only is explicitly stated in the Cryptoki
+       //    specification; however, a particular library and token may be even more restrictive than
+       //    Cryptoki specifies. In other words, an attribute which Cryptoki says is not read-only may
+       //    nonetheless be read-only under certain circumstances (i.e., in conjunction with some
+       //    combinations of other attributes) for a particular library and token. Whether or not a
+       //    given non-Cryptoki attribute is read-only is obviously outside the scope of Cryptoki.
+
+       // Attributes cannot be changed if CKA_MODIFIABLE is set to false
+       if (!isModifiable() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE) {
+               ERROR_MSG("An object is with CKA_MODIFIABLE set to false is not modifiable");
+               return CKR_ATTRIBUTE_READ_ONLY;
+       }
+
+       // Attributes cannot be modified if CKA_TRUSTED is true on a certificate object.
+       if (isTrusted() && op != OBJECT_OP_GENERATE && op != OBJECT_OP_CREATE) {
+               if (osobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_CERTIFICATE)
+               {
+                       ERROR_MSG("A trusted certificate cannot be modified");
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       //  ck2  MUST not be specified when object is created with C_CreateObject.
+       if ((checks & ck2) == ck2)
+       {
+               if (OBJECT_OP_CREATE==op)
+               {
+                       ERROR_MSG("Prohibited attribute was passed to object creation function");
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       //  ck4  MUST not be specified when object is generated with C_GenerateKey or C_GenerateKeyPair.
+       if ((checks & ck4) == ck4)
+       {
+               if (OBJECT_OP_GENERATE==op)
+               {
+                       ERROR_MSG("Prohibited attribute was passed to key generation function");
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       //  ck6  MUST not be specified when object is unwrapped with C_UnwrapKey.
+       if ((checks & ck6) == ck6)
+       {
+               if (OBJECT_OP_UNWRAP==op)
+               {
+                       ERROR_MSG("Prohibited attribute was passed to key unwrapping function");
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       //  ck8  May be modified after object is created with a C_SetAttributeValue call
+       //       or in the process of copying an object with a C_CopyObject call.
+       //       However, it is possible that a particular token may not permit modification of
+       //       the attribute during the course of a C_CopyObject call.
+       if ((checks & ck8) == ck8)
+       {
+               if (OBJECT_OP_SET==op || OBJECT_OP_COPY==op)
+               {
+                       return updateAttr(token, isPrivate, pValue, ulValueLen, op);
+               }
+       }
+
+       // ck17  Can be changed in the process of copying the object using C_CopyObject.
+       if ((checks & ck17) == ck17)
+       {
+               if (OBJECT_OP_COPY==op)
+               {
+                       return updateAttr(token, isPrivate, pValue, ulValueLen, op);
+               }
+       }
+
+       // For attributes that have not been explicitly excluded from modification
+       // during create/derive/generate/unwrap, we allow them to be modified.
+       if (OBJECT_OP_CREATE==op || OBJECT_OP_DERIVE==op || OBJECT_OP_GENERATE==op || OBJECT_OP_UNWRAP==op)
+       {
+               return updateAttr(token, isPrivate, pValue, ulValueLen, op);
+       }
+
+       return CKR_ATTRIBUTE_READ_ONLY;
+}
+
+/*****************************************
+ * CKA_CLASS
+ *****************************************/
+
+// Set default value
+bool P11AttrClass::setDefault()
+{
+       OSAttribute attrClass((unsigned long)CKO_VENDOR_DEFINED);
+       return osobject->setAttribute(type, attrClass);
+}
+
+// Update the value if allowed
+CK_RV P11AttrClass::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       if (osobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != *(CK_ULONG*)pValue)
+       {
+               return CKR_TEMPLATE_INCONSISTENT;
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_KEY_TYPE
+ *****************************************/
+
+// Set default value
+bool P11AttrKeyType::setDefault()
+{
+       OSAttribute attr((unsigned long)CKK_VENDOR_DEFINED);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrKeyType::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       if (osobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != *(CK_ULONG*)pValue)
+       {
+               return CKR_TEMPLATE_INCONSISTENT;
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_CERTIFICATE_TYPE
+ * footnote 1
+ *  1  MUST be specified when object is created with C_CreateObject.
+ *****************************************/
+
+// Set default value
+bool P11AttrCertificateType::setDefault()
+{
+       OSAttribute attr((unsigned long)CKC_VENDOR_DEFINED);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrCertificateType::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       if (osobject->getUnsignedLongValue(CKA_CERTIFICATE_TYPE, CKC_VENDOR_DEFINED) != *(CK_ULONG*)pValue)
+       {
+               return CKR_TEMPLATE_INCONSISTENT;
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_TOKEN
+ *****************************************/
+
+// Set default value
+bool P11AttrToken::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrToken::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_PRIVATE
+ *****************************************/
+
+// Set default value
+bool P11AttrPrivate::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrPrivate::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_MODIFIABLE
+ *****************************************/
+
+// Set default value
+bool P11AttrModifiable::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrModifiable::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_LABEL
+ *****************************************/
+
+// Set default value
+bool P11AttrLabel::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_COPYABLE
+ *****************************************/
+
+// Set default value
+bool P11AttrCopyable::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrCopyable::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               if (osobject->getBooleanValue(CKA_COPYABLE, true) == false)
+               {
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_DESTROYABLE
+ *****************************************/
+
+// Set default value
+bool P11AttrDestroyable::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrDestroyable::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_APPLICATION
+ *****************************************/
+
+// Set default value
+bool P11AttrApplication::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_OBJECT_ID
+ *****************************************/
+
+// Set default value
+bool P11AttrObjectID::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_CHECK_VALUE
+ *****************************************/
+
+// Set default value
+bool P11AttrCheckValue::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrCheckValue::updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       ByteString plaintext((unsigned char*)pValue, ulValueLen);
+       ByteString value;
+
+       // Encrypt
+
+       if (isPrivate)
+       {
+               if (!token->encrypt(plaintext, value))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+               value = plaintext;
+
+       // Attribute specific checks
+
+       if (value.size() < ulValueLen)
+               return CKR_GENERAL_ERROR;
+
+       // Store data
+       if (ulValueLen == 0)
+       {
+               osobject->setAttribute(type, value);
+       }
+       else
+       {
+               ByteString checkValue;
+               ByteString keybits;
+               if (isPrivate)
+               {
+                       if (!token->decrypt(osobject->getByteStringValue(CKA_VALUE), keybits))
+                               return CKR_GENERAL_ERROR;
+               }
+               else
+               {
+                       keybits = osobject->getByteStringValue(CKA_VALUE);
+               }
+
+               SymmetricKey key;
+               AESKey aes;
+               DESKey des;
+               switch (osobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED))
+               {
+                       case CKK_GENERIC_SECRET:
+                       case CKK_MD5_HMAC:
+                       case CKK_SHA_1_HMAC:
+                       case CKK_SHA224_HMAC:
+                       case CKK_SHA256_HMAC:
+                       case CKK_SHA384_HMAC:
+                       case CKK_SHA512_HMAC:
+                               key.setKeyBits(keybits);
+                               key.setBitLen(keybits.size() * 8);
+                               checkValue = key.getKeyCheckValue();
+                               break;
+                       case CKK_AES:
+                               aes.setKeyBits(keybits);
+                               aes.setBitLen(keybits.size() * 8);
+                               checkValue = aes.getKeyCheckValue();
+                               break;
+                       case CKK_DES:
+                       case CKK_DES2:
+                       case CKK_DES3:
+                               des.setKeyBits(keybits);
+                               des.setBitLen(keybits.size() * 7);
+                               checkValue = des.getKeyCheckValue();
+                               break;
+                       case CKK_GOST28147:
+                               // TODO: Encryption support for CKK_GOST28147
+                               // We do not calculate the KCV
+                               checkValue = plaintext;
+                               break;
+                       default:
+                               return CKR_GENERAL_ERROR;
+               }
+
+               if (plaintext != checkValue)
+                       return CKR_ATTRIBUTE_VALUE_INVALID;
+
+               osobject->setAttribute(type, value);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_PUBLIC_KEY_INFO
+ *****************************************/
+
+// Set default value
+bool P11AttrPublicKeyInfo::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_ID
+ *****************************************/
+
+// Set default value
+bool P11AttrID::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_VALUE
+ *****************************************/
+
+// Set default value
+bool P11AttrValue::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrValue::updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       ByteString plaintext((unsigned char*)pValue, ulValueLen);
+       ByteString value;
+
+       // Encrypt
+
+       if (isPrivate)
+       {
+               if (!token->encrypt(plaintext, value))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+               value = plaintext;
+
+       // Attribute specific checks
+
+       if (value.size() < ulValueLen)
+               return CKR_GENERAL_ERROR;
+
+       // Store data
+
+       osobject->setAttribute(type, value);
+
+       // Set the size during C_CreateObject and C_UnwrapKey.
+
+       if (op == OBJECT_OP_CREATE || op == OBJECT_OP_UNWRAP)
+       {
+               // Set the CKA_VALUE_LEN
+               if (osobject->attributeExists(CKA_VALUE_LEN))
+               {
+                       OSAttribute bytes((unsigned long)plaintext.size());
+                       osobject->setAttribute(CKA_VALUE_LEN, bytes);
+               }
+
+               // Set the CKA_VALUE_BITS
+               if (osobject->attributeExists(CKA_VALUE_BITS))
+               {
+                       OSAttribute bits((unsigned long)plaintext.bits());
+                       osobject->setAttribute(CKA_VALUE_BITS, bits);
+               }
+       }
+
+       // Calculate the CKA_CHECK_VALUE for certificates
+       if (osobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_CERTIFICATE)
+       {
+               HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
+               if (hash == NULL) return CKR_GENERAL_ERROR;
+
+               ByteString digest;
+               if (hash->hashInit() == false ||
+                   hash->hashUpdate(plaintext) == false ||
+                   hash->hashFinal(digest) == false)
+               {
+                       CryptoFactory::i()->recycleHashAlgorithm(hash);
+                       return CKR_GENERAL_ERROR;
+               }
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+               // First three bytes of the SHA-1 hash
+               digest.resize(3);
+
+               if (isPrivate)
+               {
+                       ByteString encrypted;
+                       if (!token->encrypt(digest, encrypted))
+                               return CKR_GENERAL_ERROR;
+                       osobject->setAttribute(CKA_CHECK_VALUE, encrypted);
+               }
+               else
+                       osobject->setAttribute(CKA_CHECK_VALUE, digest);
+       }
+
+       // Calculate the CKA_CHECK_VALUE for secret keys
+       if (op == OBJECT_OP_CREATE &&
+           osobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_SECRET_KEY)
+       {
+               SymmetricKey key;
+               AESKey aes;
+               DESKey des;
+               ByteString checkValue;
+               switch (osobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED))
+               {
+                       case CKK_GENERIC_SECRET:
+                       case CKK_MD5_HMAC:
+                       case CKK_SHA_1_HMAC:
+                       case CKK_SHA224_HMAC:
+                       case CKK_SHA256_HMAC:
+                       case CKK_SHA384_HMAC:
+                       case CKK_SHA512_HMAC:
+                               key.setKeyBits(plaintext);
+                               key.setBitLen(plaintext.size() * 8);
+                               checkValue = key.getKeyCheckValue();
+                               break;
+                       case CKK_AES:
+                               aes.setKeyBits(plaintext);
+                               aes.setBitLen(plaintext.size() * 8);
+                               checkValue = aes.getKeyCheckValue();
+                               break;
+                       case CKK_DES:
+                       case CKK_DES2:
+                       case CKK_DES3:
+                               des.setKeyBits(plaintext);
+                               des.setBitLen(plaintext.size() * 7);
+                               checkValue = des.getKeyCheckValue();
+                               break;
+                       case CKK_GOST28147:
+                               // TODO: Encryption support for CKK_GOST28147
+                               // We do not calculate the KCV
+                               break;
+                       default:
+                               return CKR_GENERAL_ERROR;
+               }
+
+               if (isPrivate)
+               {
+                       ByteString encrypted;
+                       if (!token->encrypt(checkValue, encrypted))
+                               return CKR_GENERAL_ERROR;
+                       osobject->setAttribute(CKA_CHECK_VALUE, encrypted);
+               }
+               else
+                       osobject->setAttribute(CKA_CHECK_VALUE, checkValue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_SUBJECT
+ *****************************************/
+
+// Set default value
+bool P11AttrSubject::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_ISSUER
+ *****************************************/
+
+// Set default value
+bool P11AttrIssuer::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_TRUSTED
+ *****************************************/
+
+// Set default value
+bool P11AttrTrusted::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrTrusted::updateAttr(Token *token, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               if (!token->isSOLoggedIn())
+               {
+                       ERROR_MSG("CKA_TRUSTED can only be set to true by the SO");
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_CERTIFICATE_CATEGORY
+ *****************************************/
+
+// Set default value
+bool P11AttrCertificateCategory::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrCertificateCategory::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_START_DATE
+ *****************************************/
+
+// Set default value
+bool P11AttrStartDate::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrStartDate::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_DATE) && ulValueLen !=0)
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+       osobject->setAttribute(type, ByteString((unsigned char*)pValue, ulValueLen));
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_END_DATE
+ *****************************************/
+
+// Set default value
+bool P11AttrEndDate::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrEndDate::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_DATE) && ulValueLen !=0)
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+       osobject->setAttribute(type, ByteString((unsigned char*)pValue, ulValueLen));
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_SERIAL_NUMBER
+ *****************************************/
+
+// Set default value
+bool P11AttrSerialNumber::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_URL
+ *****************************************/
+
+// Set default value
+bool P11AttrURL::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_HASH_OF_SUBJECT_PUBLIC_KEY
+ *****************************************/
+
+// Set default value
+bool P11AttrHashOfSubjectPublicKey::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_HASH_OF_ISSUER_PUBLIC_KEY
+ *****************************************/
+
+// Set default value
+bool P11AttrHashOfIssuerPublicKey::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_JAVA_MIDP_SECURITY_DOMAIN
+ *****************************************/
+
+// Set default value
+bool P11AttrJavaMidpSecurityDomain::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrJavaMidpSecurityDomain::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_NAME_HASH_ALGORITHM
+ *****************************************/
+
+// Set default value
+bool P11AttrNameHashAlgorithm::setDefault()
+{
+       OSAttribute attr((unsigned long)CKM_SHA_1);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrNameHashAlgorithm::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_DERIVE
+ *****************************************/
+
+// Set default value
+bool P11AttrDerive::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrDerive::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_ENCRYPT
+ *****************************************/
+
+// Set default value
+bool P11AttrEncrypt::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrEncrypt::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_VERIFY
+ *****************************************/
+
+// Set default value
+bool P11AttrVerify::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrVerify::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_VERIFY_RECOVER
+ *****************************************/
+
+// Set default value
+bool P11AttrVerifyRecover::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrVerifyRecover::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_WRAP
+ *****************************************/
+
+// Set default value
+bool P11AttrWrap::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrWrap::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_DECRYPT
+ *****************************************/
+
+// Set default value
+bool P11AttrDecrypt::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrDecrypt::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_SIGN
+ *****************************************/
+
+// Set default value
+bool P11AttrSign::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrSign::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_SIGN_RECOVER
+ *****************************************/
+
+// Set default value
+bool P11AttrSignRecover::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrSignRecover::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_UNWRAP
+ *****************************************/
+
+// Set default value
+bool P11AttrUnwrap::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrUnwrap::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_LOCAL
+ *****************************************/
+
+// Set default value
+bool P11AttrLocal::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrLocal::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR /*pValue*/, CK_ULONG /*ulValueLen*/, int /*op*/)
+{
+       return CKR_ATTRIBUTE_READ_ONLY;
+}
+
+/*****************************************
+ * CKA_KEY_GEN_MECHANISM
+ *****************************************/
+
+// Set default value
+bool P11AttrKeyGenMechanism::setDefault()
+{
+       OSAttribute attr((unsigned long)CK_UNAVAILABLE_INFORMATION);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrKeyGenMechanism::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR /*pValue*/, CK_ULONG /*ulValueLen*/, int /*op*/)
+{
+       return CKR_ATTRIBUTE_READ_ONLY;
+}
+
+/*****************************************
+ * CKA_ALWAYS_SENSITIVE
+ *****************************************/
+
+// Set default value
+bool P11AttrAlwaysSensitive::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrAlwaysSensitive::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR /*pValue*/, CK_ULONG /*ulValueLen*/, int /*op*/)
+{
+       return CKR_ATTRIBUTE_READ_ONLY;
+}
+
+/*****************************************
+ * CKA_NEVER_EXTRACTABLE
+ *****************************************/
+
+// Set default value
+bool P11AttrNeverExtractable::setDefault()
+{
+       OSAttribute attr(true);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrNeverExtractable::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR /*pValue*/, CK_ULONG /*ulValueLen*/, int /*op*/)
+{
+       return CKR_ATTRIBUTE_READ_ONLY;
+}
+
+/*****************************************
+ * CKA_SENSITIVE
+ *****************************************/
+
+// Set default value
+bool P11AttrSensitive::setDefault()
+{
+       // We default to false because we want to handle the secret keys in a correct way
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrSensitive::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (op == OBJECT_OP_SET || op == OBJECT_OP_COPY)
+       {
+               if (osobject->getBooleanValue(CKA_SENSITIVE, false))
+               {
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+               osobject->setAttribute(CKA_ALWAYS_SENSITIVE, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+
+               // This is so that generated keys get the correct value
+               if (op == OBJECT_OP_GENERATE || op == OBJECT_OP_DERIVE)
+               {
+                       osobject->setAttribute(CKA_ALWAYS_SENSITIVE, attrTrue);
+               }
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_EXTRACTABLE
+ *****************************************/
+
+// Set default value
+bool P11AttrExtractable::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrExtractable::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (op == OBJECT_OP_SET || op == OBJECT_OP_COPY)
+       {
+               if (osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false)
+               {
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+               osobject->setAttribute(CKA_NEVER_EXTRACTABLE, attrFalse);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_WRAP_WITH_TRUSTED
+ *****************************************/
+
+// Set default value
+bool P11AttrWrapWithTrusted::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrWrapWithTrusted::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (op == OBJECT_OP_SET || op == OBJECT_OP_COPY)
+       {
+               if (osobject->getBooleanValue(CKA_WRAP_WITH_TRUSTED, false))
+               {
+                       return CKR_ATTRIBUTE_READ_ONLY;
+               }
+       }
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_ALWAYS_AUTHENTICATE
+ *****************************************/
+
+// Set default value
+bool P11AttrAlwaysAuthenticate::setDefault()
+{
+       OSAttribute attr(false);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrAlwaysAuthenticate::updateAttr(Token* /*token*/, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       OSAttribute attrTrue(true);
+       OSAttribute attrFalse(false);
+
+       // Attribute specific checks
+
+       if (ulValueLen !=sizeof(CK_BBOOL))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       if (*(CK_BBOOL*)pValue == CK_FALSE)
+       {
+               osobject->setAttribute(type, attrFalse);
+       }
+       else
+       {
+               if (!isPrivate)
+               {
+                       return CKR_TEMPLATE_INCONSISTENT;
+               }
+
+               osobject->setAttribute(type, attrTrue);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_MODULUS
+ *****************************************/
+
+// Set default value
+bool P11AttrModulus::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrModulus::updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       ByteString plaintext((unsigned char*)pValue, ulValueLen);
+       ByteString value;
+
+       // Encrypt
+
+       if (isPrivate)
+       {
+               if (!token->encrypt(plaintext, value))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+               value = plaintext;
+
+       // Attribute specific checks
+
+       if (value.size() < ulValueLen)
+               return CKR_GENERAL_ERROR;
+
+       // Store data
+
+       osobject->setAttribute(type, value);
+
+       // Set the CKA_MODULUS_BITS during C_CreateObject
+
+       if (op == OBJECT_OP_CREATE && osobject->attributeExists(CKA_MODULUS_BITS))
+       {
+               OSAttribute bits((unsigned long)plaintext.bits());
+               osobject->setAttribute(CKA_MODULUS_BITS, bits);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_PUBLIC_EXPONENT
+ *****************************************/
+
+// Set default value
+bool P11AttrPublicExponent::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_PRIVATE_EXPONENT
+ *****************************************/
+
+// Set default value
+bool P11AttrPrivateExponent::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_PRIME_1
+ *****************************************/
+
+// Set default value
+bool P11AttrPrime1::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_PRIME_2
+ *****************************************/
+
+// Set default value
+bool P11AttrPrime2::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_EXPONENT_1
+ *****************************************/
+
+// Set default value
+bool P11AttrExponent1::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_EXPONENT_2
+ *****************************************/
+
+// Set default value
+bool P11AttrExponent2::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_COEFFICIENT
+ *****************************************/
+
+// Set default value
+bool P11AttrCoefficient::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_MODULUS_BITS
+ *****************************************/
+
+// Set default value
+bool P11AttrModulusBits::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrModulusBits::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       // Attribute specific checks
+
+       if (op != OBJECT_OP_GENERATE)
+       {
+               return CKR_ATTRIBUTE_READ_ONLY;
+       }
+
+       if (ulValueLen !=sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_PRIME
+ *****************************************/
+
+// Set default value
+bool P11AttrPrime::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrPrime::updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       ByteString plaintext((unsigned char*)pValue, ulValueLen);
+       ByteString value;
+
+       // Encrypt
+
+       if (isPrivate)
+       {
+               if (!token->encrypt(plaintext, value))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+               value = plaintext;
+
+       // Attribute specific checks
+
+       if (value.size() < ulValueLen)
+               return CKR_GENERAL_ERROR;
+
+       // Store data
+
+       osobject->setAttribute(type, value);
+
+       // Set the CKA_PRIME_BITS during C_CreateObject
+
+       if (op == OBJECT_OP_CREATE && osobject->attributeExists(CKA_PRIME_BITS))
+       {
+               OSAttribute bits((unsigned long)plaintext.bits());
+               osobject->setAttribute(CKA_PRIME_BITS, bits);
+       }
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_SUBPRIME
+ *****************************************/
+
+// Set default value
+bool P11AttrSubPrime::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_BASE
+ *****************************************/
+
+// Set default value
+bool P11AttrBase::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_PRIME_BITS
+ *****************************************/
+
+// Set default value
+bool P11AttrPrimeBits::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrPrimeBits::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       // Attribute specific checks
+
+       if (op != OBJECT_OP_GENERATE)
+       {
+               return CKR_ATTRIBUTE_READ_ONLY;
+       }
+
+       if (ulValueLen != sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_VALUE_BITS
+ *****************************************/
+
+// Set default value
+bool P11AttrValueBits::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrValueBits::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       // Attribute specific checks
+
+       if (op != OBJECT_OP_GENERATE)
+       {
+               return CKR_ATTRIBUTE_READ_ONLY;
+       }
+
+       if (ulValueLen != sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_EC_PARAMS
+ *****************************************/
+
+// Set default value
+bool P11AttrEcParams::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_EC_POINT
+ *****************************************/
+
+// Set default value
+bool P11AttrEcPoint::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_GOSTR3410_PARAMS
+ *****************************************/
+
+// Set default value
+bool P11AttrGostR3410Params::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_GOSTR3411_PARAMS
+ *****************************************/
+
+// Set default value
+bool P11AttrGostR3411Params::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_GOST28147_PARAMS
+ *****************************************/
+
+// Set default value
+bool P11AttrGost28147Params::setDefault()
+{
+       OSAttribute attr(ByteString(""));
+       return osobject->setAttribute(type, attr);
+}
+
+/*****************************************
+ * CKA_VALUE_LEN
+ *****************************************/
+
+// Set default value
+bool P11AttrValueLen::setDefault()
+{
+       OSAttribute attr((unsigned long)0);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value if allowed
+CK_RV P11AttrValueLen::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op)
+{
+       // Attribute specific checks
+
+       if (op != OBJECT_OP_GENERATE && op != OBJECT_OP_DERIVE)
+       {
+               return CKR_ATTRIBUTE_READ_ONLY;
+       }
+
+       if (ulValueLen != sizeof(CK_ULONG))
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Store data
+
+       osobject->setAttribute(type, *(CK_ULONG*)pValue);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_WRAP_TEMPLATE
+ *****************************************/
+
+// Set default value
+bool P11AttrWrapTemplate::setDefault()
+{
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> empty;
+       OSAttribute attr(empty);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value
+CK_RV P11AttrWrapTemplate::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+       if ((ulValueLen % sizeof(CK_ATTRIBUTE)) != 0)
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Fill the template vector with elements
+       CK_ATTRIBUTE_PTR attr = (CK_ATTRIBUTE_PTR) pValue;
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> data;
+       for (size_t i = 0; i < ulValueLen / sizeof(CK_ATTRIBUTE); ++i, ++attr)
+       // Specialization for known attributes
+       switch (attr->type)
+       {
+       case CKA_TOKEN:
+       case CKA_PRIVATE:
+       case CKA_MODIFIABLE:
+       case CKA_COPYABLE:
+       case CKA_TRUSTED:
+       case CKA_ENCRYPT:
+       case CKA_DECRYPT:
+       case CKA_SIGN:
+       case CKA_SIGN_RECOVER:
+       case CKA_VERIFY:
+       case CKA_VERIFY_RECOVER:
+       case CKA_WRAP:
+       case CKA_UNWRAP:
+       case CKA_DERIVE:
+       case CKA_LOCAL:
+       case CKA_ALWAYS_SENSITIVE:
+       case CKA_SENSITIVE:
+       case CKA_NEVER_EXTRACTABLE:
+       case CKA_EXTRACTABLE:
+       case CKA_WRAP_WITH_TRUSTED:
+       case CKA_SECONDARY_AUTH:
+       case CKA_ALWAYS_AUTHENTICATE:
+               {
+                       // CK_BBOOL
+                       if (attr->ulValueLen != sizeof(CK_BBOOL))
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       bool elem = (*(CK_BBOOL*)attr->pValue != CK_FALSE);
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+               break;
+
+       case CKA_CLASS:
+       case CKA_KEY_TYPE:
+       case CKA_CERTIFICATE_TYPE:
+       case CKA_CERTIFICATE_CATEGORY:
+       case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+       case CKA_NAME_HASH_ALGORITHM:
+       case CKA_KEY_GEN_MECHANISM:
+       case CKA_MODULUS_BITS:
+       case CKA_PRIME_BITS:
+       case CKA_SUBPRIME_BITS:
+       case CKA_VALUE_BITS:
+       case CKA_VALUE_LEN:
+       case CKA_AUTH_PIN_FLAGS:
+               {
+                       // CK_ULONG
+                       if (attr->ulValueLen != sizeof(CK_ULONG))
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       unsigned long elem = *(CK_ULONG*)attr->pValue;
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+               break;
+
+       case CKA_WRAP_TEMPLATE:
+       case CKA_UNWRAP_TEMPLATE:
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+
+       default:
+               {
+                       // CK_BYTE
+                       ByteString elem = ByteString((unsigned char*)attr->pValue, attr->ulValueLen);
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+       }
+
+       // Store data
+       osobject->setAttribute(type, data);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_UNWRAP_TEMPLATE
+ *****************************************/
+
+// Set default value
+bool P11AttrUnwrapTemplate::setDefault()
+{
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> empty;
+       OSAttribute attr(empty);
+       return osobject->setAttribute(type, attr);
+}
+
+// Update the value
+CK_RV P11AttrUnwrapTemplate::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       // Attribute specific checks
+       if ((ulValueLen % sizeof(CK_ATTRIBUTE)) != 0)
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Fill the template vector with elements
+       CK_ATTRIBUTE_PTR attr = (CK_ATTRIBUTE_PTR) pValue;
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> data;
+       for (size_t i = 0; i < ulValueLen / sizeof(CK_ATTRIBUTE); ++i, ++attr)
+       // Specialization for known attributes
+       switch (attr->type)
+       {
+       case CKA_TOKEN:
+       case CKA_PRIVATE:
+       case CKA_MODIFIABLE:
+       case CKA_COPYABLE:
+       case CKA_TRUSTED:
+       case CKA_ENCRYPT:
+       case CKA_DECRYPT:
+       case CKA_SIGN:
+       case CKA_SIGN_RECOVER:
+       case CKA_VERIFY:
+       case CKA_VERIFY_RECOVER:
+       case CKA_WRAP:
+       case CKA_UNWRAP:
+       case CKA_DERIVE:
+       case CKA_LOCAL:
+       case CKA_ALWAYS_SENSITIVE:
+       case CKA_SENSITIVE:
+       case CKA_NEVER_EXTRACTABLE:
+       case CKA_EXTRACTABLE:
+       case CKA_WRAP_WITH_TRUSTED:
+       case CKA_SECONDARY_AUTH:
+       case CKA_ALWAYS_AUTHENTICATE:
+               {
+                       // CK_BBOOL
+                       if (attr->ulValueLen != sizeof(CK_BBOOL))
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       bool elem = (*(CK_BBOOL*)attr->pValue != CK_FALSE);
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+               break;
+
+       case CKA_CLASS:
+       case CKA_KEY_TYPE:
+       case CKA_CERTIFICATE_TYPE:
+       case CKA_CERTIFICATE_CATEGORY:
+       case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+       case CKA_NAME_HASH_ALGORITHM:
+       case CKA_KEY_GEN_MECHANISM:
+       case CKA_MODULUS_BITS:
+       case CKA_PRIME_BITS:
+       case CKA_SUBPRIME_BITS:
+       case CKA_VALUE_BITS:
+       case CKA_VALUE_LEN:
+       case CKA_AUTH_PIN_FLAGS:
+               {
+                       // CK_ULONG
+                       if (attr->ulValueLen != sizeof(CK_ULONG))
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       unsigned long elem = *(CK_ULONG*)attr->pValue;
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+               break;
+
+       case CKA_WRAP_TEMPLATE:
+       case CKA_UNWRAP_TEMPLATE:
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+
+       default:
+               {
+                       // CK_BYTE
+                       ByteString elem = ByteString((unsigned char*)attr->pValue, attr->ulValueLen);
+                       data.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attr->type, elem));
+               }
+       }
+
+       // Store data
+       osobject->setAttribute(type, data);
+
+       return CKR_OK;
+}
+
+/*****************************************
+ * CKA_ALLOWED_MECHANISMS
+ *****************************************/
+
+// Set default value
+bool P11AttrAllowedMechanisms::setDefault()
+{
+       std::set<CK_MECHANISM_TYPE> emptyMap;
+       return osobject->setAttribute(type, OSAttribute(emptyMap));
+}
+
+// Update the value if allowed
+CK_RV P11AttrAllowedMechanisms::updateAttr(Token* /*token*/, bool /*isPrivate*/, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int /*op*/)
+{
+       if (ulValueLen == 0 || (ulValueLen % sizeof(CK_MECHANISM_TYPE)) != 0)
+       {
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       CK_MECHANISM_TYPE_PTR mechType = (CK_MECHANISM_TYPE_PTR) pValue;
+
+       // Fill the set with values
+       std::set<CK_MECHANISM_TYPE> data;
+       for (size_t i = 0; i < ulValueLen / sizeof(CK_MECHANISM_TYPE); ++i, ++mechType)
+       {
+               data.insert(*mechType);
+       }
+
+       // Store data
+       osobject->setAttribute(type, OSAttribute(data));
+       return CKR_OK;
+}
diff --git a/SoftHSMv2/src/lib/P11Attributes.h b/SoftHSMv2/src/lib/P11Attributes.h
new file mode 100644 (file)
index 0000000..3cddf30
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ P11Attributes.h
+
+ This file contains classes for controlling attributes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_P11ATTRIBUTES_H
+#define _SOFTHSM_V2_P11ATTRIBUTES_H
+
+#include "cryptoki.h"
+#include "OSObject.h"
+#include "Token.h"
+
+// The operation types
+#define OBJECT_OP_NONE         0x0
+#define OBJECT_OP_COPY         0x1
+#define OBJECT_OP_CREATE       0x2
+#define OBJECT_OP_DERIVE       0x3
+#define OBJECT_OP_GENERATE     0x4
+#define OBJECT_OP_SET          0x5
+#define OBJECT_OP_UNWRAP       0x6
+
+class P11Attribute
+{
+public:
+       // Destructor
+       virtual ~P11Attribute();
+
+       // Initialize the attribute
+       bool init();
+
+       // Return the attribute type
+       CK_ATTRIBUTE_TYPE getType();
+
+       // Return the attribute checks
+       CK_ULONG getChecks();
+
+       // Retrieve the value if allowed
+       CK_RV retrieve(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG_PTR pulValueLen);
+
+       // Update the value if allowed
+       CK_RV update(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+
+       // Checks are determined by footnotes from table 10 under section 4.2 in the PKCS#11 v2.40 spec.
+       // Table 10 contains common footnotes for object attribute tables that determine the checks to perform on attributes.
+       // There are also checks not in table 10 that have been added here to allow enforcing additional contraints.
+       enum {
+               ck1=1,          //  1  MUST be specified when object is created with C_CreateObject.
+               ck2=2,          //  2  MUST not be specified when object is created with C_CreateObject.
+               ck3=4,          //  3  MUST be specified when object is generated with C_GenerateKey or C_GenerateKeyPair.
+               ck4=8,          //  4  MUST not be specified when object is generated with C_GenerateKey or C_GenerateKeyPair.
+               ck5=0x10,       //  5  MUST be specified when object is unwrapped with C_UnwrapKey.
+               ck6=0x20,       //  6  MUST not be specified when object is unwrapped with C_UnwrapKey.
+               ck7=0x40,       //  7  Cannot be revealed if object has its CKA_SENSITIVE attribute set to CK_TRUE or
+                               //      its CKA_EXTRACTABLE attribute set to CK_FALSE.
+               ck8=0x80,       //  8  May be modified after object is created with a C_SetAttributeValue call,
+                               //      or in the process of copying object with a C_CopyObject call.
+                               //      However, it is possible that a particular token may not permit modification of
+                               //      the attribute during the course of a C_CopyObject call.
+               ck9=0x100,      //  9  Default value is token-specific, and may depend on the values of other attributes.
+               ck10=0x200,     // 10  Can only be set to CK_TRUE by the SO user.
+               ck11=0x400,     // 11  Attribute cannot be changed once set to CK_TRUE. It becomes a read only attribute.
+               ck12=0x800,     // 12  Attribute cannot be changed once set to CK_FALSE. It becomes a read only attribute.
+               ck13=0x1000,    // Intentionally not defined
+               ck14=0x2000,    // 14  MUST be non-empty if CKA_URL is empty. (CKA_VALUE)
+               ck15=0x4000,    // 15  MUST be non-empty if CKA_VALUE is empty. (CKA_URL)
+               ck16=0x8000,    // 16  Can only be empty if CKA_URL is empty.
+               ck17=0x10000,   // 17  Can be changed in the process of copying the object using C_CopyObject.
+               ck18=0x20000,
+               ck19=0x40000,
+               ck20=0x80000,
+               ck21=0x100000,
+               ck22=0x200000,
+               ck23=0x400000,
+               ck24=0x800000
+       };
+protected:
+       // Constructor
+       P11Attribute(OSObject* inobject);
+
+       // The object
+       OSObject* osobject;
+
+       // The attribute type
+       CK_ATTRIBUTE_TYPE type;
+
+       // The checks to perform when the attribute is accessed.
+       CK_ULONG checks;
+
+       // The attribute fixed size contains (CK_ULONG)-1 when size is variable.
+       CK_ULONG size;
+
+       // Set the default value of the attribute
+       virtual bool setDefault() = 0;
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+
+       // Helper functions
+       bool isModifiable();
+       bool isSensitive();
+       bool isExtractable();
+       bool isTrusted();
+};
+
+/*****************************************
+ * CKA_CLASS
+ *****************************************/
+
+class P11AttrClass : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrClass(OSObject* inobject) : P11Attribute(inobject) { type = CKA_CLASS; size = sizeof(CK_OBJECT_CLASS); checks = ck1; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_KEY_TYPE
+ *****************************************/
+
+class P11AttrKeyType : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrKeyType(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_KEY_TYPE; size = sizeof(CK_KEY_TYPE); checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_CERTIFICATE_TYPE
+ *****************************************/
+
+class P11AttrCertificateType : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrCertificateType(OSObject* inobject) : P11Attribute(inobject) { type = CKA_CERTIFICATE_TYPE; size = sizeof(CK_CERTIFICATE_TYPE); checks = ck1; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_TOKEN
+ *****************************************/
+
+class P11AttrToken : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrToken(OSObject* inobject) : P11Attribute(inobject) { type = CKA_TOKEN; size = sizeof(CK_BBOOL); checks = ck17; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_PRIVATE
+ *****************************************/
+
+class P11AttrPrivate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrivate(OSObject* inobject) : P11Attribute(inobject) { type = CKA_PRIVATE; size = sizeof(CK_BBOOL); checks = ck17; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_MODIFIABLE
+ *****************************************/
+
+class P11AttrModifiable : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrModifiable(OSObject* inobject) : P11Attribute(inobject) { type = CKA_MODIFIABLE; size = sizeof(CK_BBOOL); checks = ck17; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_LABEL
+ *****************************************/
+
+class P11AttrLabel : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrLabel(OSObject* inobject) : P11Attribute(inobject) { type = CKA_LABEL;  checks = ck8; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_COPYABLE
+ *****************************************/
+
+class P11AttrCopyable : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrCopyable(OSObject* inobject) : P11Attribute(inobject) { type = CKA_COPYABLE; size = sizeof(CK_BBOOL); checks = ck12; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_DESTROYABLE
+ *****************************************/
+
+class P11AttrDestroyable : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrDestroyable(OSObject* inobject) : P11Attribute(inobject) { type = CKA_DESTROYABLE; size = sizeof(CK_BBOOL); checks = ck17; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_APPLICATION
+ *****************************************/
+
+class P11AttrApplication : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrApplication(OSObject* inobject) : P11Attribute(inobject) { type = CKA_APPLICATION; checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_OBJECT_ID
+ *****************************************/
+
+class P11AttrObjectID : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrObjectID(OSObject* inobject) : P11Attribute(inobject) { type = CKA_OBJECT_ID; checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_CHECK_VALUE
+ *****************************************/
+
+class P11AttrCheckValue : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrCheckValue(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_CHECK_VALUE; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_PUBLIC_KEY_INFO
+ *****************************************/
+
+class P11AttrPublicKeyInfo : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPublicKeyInfo(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_OBJECT_ID; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_ID
+ *****************************************/
+
+class P11AttrID : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrID(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ID; checks = ck8; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_VALUE
+ *****************************************/
+
+class P11AttrValue : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrValue(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_VALUE; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SUBJECT
+ *****************************************/
+
+class P11AttrSubject : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSubject(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_SUBJECT; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_ISSUER
+ *****************************************/
+
+class P11AttrIssuer : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrIssuer(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ISSUER; checks = ck8; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_TRUSTED
+ *****************************************/
+
+class P11AttrTrusted : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrTrusted(OSObject* inobject) : P11Attribute(inobject) { type = CKA_TRUSTED; size = sizeof(CK_BBOOL); checks = ck10; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_CERTIFICATE_CATEGORY
+ *****************************************/
+
+class P11AttrCertificateCategory : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrCertificateCategory(OSObject* inobject) : P11Attribute(inobject) { type = CKA_CERTIFICATE_CATEGORY; size = sizeof(CK_ULONG); checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_START_DATE
+ *****************************************/
+
+class P11AttrStartDate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrStartDate(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_START_DATE; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_END_DATE
+ *****************************************/
+
+class P11AttrEndDate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrEndDate(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_END_DATE; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SERIAL_NUMBER
+ *****************************************/
+
+class P11AttrSerialNumber : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSerialNumber(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SERIAL_NUMBER; checks = ck8; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_URL
+ *****************************************/
+
+class P11AttrURL : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrURL(OSObject* inobject) : P11Attribute(inobject) { type = CKA_URL; checks = ck15; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_HASH_OF_SUBJECT_PUBLIC_KEY
+ *****************************************/
+
+class P11AttrHashOfSubjectPublicKey : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrHashOfSubjectPublicKey(OSObject* inobject) : P11Attribute(inobject) { type = CKA_HASH_OF_SUBJECT_PUBLIC_KEY; checks = ck16; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_HASH_OF_ISSUER_PUBLIC_KEY
+ *****************************************/
+
+class P11AttrHashOfIssuerPublicKey : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrHashOfIssuerPublicKey(OSObject* inobject) : P11Attribute(inobject) { type = CKA_HASH_OF_ISSUER_PUBLIC_KEY; checks = ck16; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_JAVA_MIDP_SECURITY_DOMAIN
+ *****************************************/
+
+class P11AttrJavaMidpSecurityDomain : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrJavaMidpSecurityDomain(OSObject* inobject) : P11Attribute(inobject) { type = CKA_JAVA_MIDP_SECURITY_DOMAIN; size = sizeof(CK_ULONG); checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_NAME_HASH_ALGORITHM
+ *****************************************/
+
+class P11AttrNameHashAlgorithm : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrNameHashAlgorithm(OSObject* inobject) : P11Attribute(inobject) { type = CKA_NAME_HASH_ALGORITHM; size = sizeof(CK_MECHANISM_TYPE); checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_DERIVE
+ *****************************************/
+
+class P11AttrDerive : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrDerive(OSObject* inobject) : P11Attribute(inobject) { type = CKA_DERIVE; size = sizeof(CK_BBOOL); checks = ck8;}
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_ENCRYPT
+ *****************************************/
+
+class P11AttrEncrypt : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrEncrypt(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ENCRYPT; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_VERIFY
+ *****************************************/
+
+class P11AttrVerify : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrVerify(OSObject* inobject) : P11Attribute(inobject) { type = CKA_VERIFY; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_VERIFY_RECOVER
+ *****************************************/
+
+class P11AttrVerifyRecover : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrVerifyRecover(OSObject* inobject) : P11Attribute(inobject) { type = CKA_VERIFY_RECOVER; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_WRAP
+ *****************************************/
+
+class P11AttrWrap : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrWrap(OSObject* inobject) : P11Attribute(inobject) { type = CKA_WRAP; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_DECRYPT
+ *****************************************/
+
+class P11AttrDecrypt : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrDecrypt(OSObject* inobject) : P11Attribute(inobject) { type = CKA_DECRYPT; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SIGN
+ *****************************************/
+
+class P11AttrSign : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSign(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SIGN; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SIGN_RECOVER
+ *****************************************/
+
+class P11AttrSignRecover : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSignRecover(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SIGN_RECOVER; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_UNWRAP
+ *****************************************/
+
+class P11AttrUnwrap : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrUnwrap(OSObject* inobject) : P11Attribute(inobject) { type = CKA_UNWRAP; size = sizeof(CK_BBOOL); checks = ck8|ck9; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_LOCAL
+ *****************************************/
+
+class P11AttrLocal : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrLocal(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_LOCAL; size = sizeof(CK_BBOOL); checks = ck2|ck4|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_KEY_GEN_MECHANISM
+ *****************************************/
+
+class P11AttrKeyGenMechanism : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrKeyGenMechanism(OSObject* inobject) : P11Attribute(inobject) { type = CKA_KEY_GEN_MECHANISM; size = sizeof(CK_MECHANISM_TYPE); checks = ck2|ck4|ck6; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_ALWAYS_SENSITIVE
+ *****************************************/
+
+class P11AttrAlwaysSensitive : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrAlwaysSensitive(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ALWAYS_SENSITIVE; size = sizeof(CK_BBOOL); checks = ck2|ck4|ck6; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_NEVER_EXTRACTABLE
+ *****************************************/
+
+class P11AttrNeverExtractable : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrNeverExtractable(OSObject* inobject) : P11Attribute(inobject) { type = CKA_NEVER_EXTRACTABLE; size = sizeof(CK_BBOOL); checks = ck2|ck4|ck6; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SENSITIVE
+ *****************************************/
+
+class P11AttrSensitive : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSensitive(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SENSITIVE; size = sizeof(CK_BBOOL); checks = ck8|ck9|ck11; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_EXTRACTABLE
+ *****************************************/
+
+class P11AttrExtractable : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrExtractable(OSObject* inobject) : P11Attribute(inobject) { type = CKA_EXTRACTABLE; size = sizeof(CK_BBOOL); checks = ck8|ck9|ck12; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_WRAP_WITH_TRUSTED
+ *****************************************/
+
+class P11AttrWrapWithTrusted : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrWrapWithTrusted(OSObject* inobject) : P11Attribute(inobject) { type = CKA_WRAP_WITH_TRUSTED; size = sizeof(CK_BBOOL); checks = ck11; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_ALWAYS_AUTHENTICATE
+ *****************************************/
+
+class P11AttrAlwaysAuthenticate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrAlwaysAuthenticate(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ALWAYS_AUTHENTICATE; size = sizeof(CK_BBOOL); checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_MODULUS
+ *****************************************/
+
+class P11AttrModulus : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrModulus(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_MODULUS; checks = ck1|ck4|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_PUBLIC_EXPONENT
+ *****************************************/
+
+class P11AttrPublicExponent : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPublicExponent(OSObject* inobject, CK_ULONG inchecks) : P11Attribute(inobject) { type = CKA_PUBLIC_EXPONENT; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_PRIVATE_EXPONENT
+ *****************************************/
+
+class P11AttrPrivateExponent : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrivateExponent(OSObject* inobject) : P11Attribute(inobject) { type = CKA_PRIVATE_EXPONENT; checks = ck1|ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_PRIME_1
+ *****************************************/
+
+class P11AttrPrime1 : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrime1(OSObject* inobject) : P11Attribute(inobject) { type = CKA_PRIME_1; checks = ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_PRIME_2
+ *****************************************/
+
+class P11AttrPrime2 : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrime2(OSObject* inobject) : P11Attribute(inobject) { type = CKA_PRIME_2; checks = ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_EXPONENT_1
+ *****************************************/
+
+class P11AttrExponent1 : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrExponent1(OSObject* inobject) : P11Attribute(inobject) { type = CKA_EXPONENT_1; checks = ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_EXPONENT_2
+ *****************************************/
+
+class P11AttrExponent2 : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrExponent2(OSObject* inobject) : P11Attribute(inobject) { type = CKA_EXPONENT_2; checks = ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_COEFFICIENT
+ *****************************************/
+
+class P11AttrCoefficient : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrCoefficient(OSObject* inobject) : P11Attribute(inobject) { type = CKA_COEFFICIENT; checks = ck4|ck6|ck7; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_MODULUS_BITS
+ *****************************************/
+
+class P11AttrModulusBits : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrModulusBits(OSObject* inobject) : P11Attribute(inobject) { type = CKA_MODULUS_BITS; size = sizeof(CK_ULONG); checks = ck2|ck3;}
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_PRIME
+ *****************************************/
+
+class P11AttrPrime : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrime(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_PRIME; checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_SUBPRIME
+ *****************************************/
+
+class P11AttrSubPrime : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrSubPrime(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_SUBPRIME; checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_BASE
+ *****************************************/
+
+class P11AttrBase : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrBase(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_BASE; checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_PRIME_BITS
+ *****************************************/
+
+class P11AttrPrimeBits : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrPrimeBits(OSObject* inobject) : P11Attribute(inobject) { type = CKA_PRIME_BITS; size = sizeof(CK_ULONG); checks = ck2|ck3;}
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_VALUE_BITS
+ *****************************************/
+
+class P11AttrValueBits : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrValueBits(OSObject* inobject) : P11Attribute(inobject) { type = CKA_VALUE_BITS; size = sizeof(CK_ULONG); checks = ck2|ck6;}
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_EC_PARAMS
+ *****************************************/
+
+class P11AttrEcParams : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrEcParams(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_EC_PARAMS; checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_EC_POINT
+ *****************************************/
+
+class P11AttrEcPoint : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrEcPoint(OSObject* inobject) : P11Attribute(inobject) { type = CKA_EC_POINT; checks = ck1|ck4; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_GOSTR3410_PARAMS
+ *****************************************/
+
+class P11AttrGostR3410Params : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrGostR3410Params(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_GOSTR3410_PARAMS; checks = ck1|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_GOSTR3411_PARAMS
+ *****************************************/
+
+class P11AttrGostR3411Params : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrGostR3411Params(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_GOSTR3411_PARAMS; checks = ck1|ck8|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_GOST28147_PARAMS
+ *****************************************/
+
+class P11AttrGost28147Params : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrGost28147Params(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_GOST28147_PARAMS; checks = inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+};
+
+/*****************************************
+ * CKA_VALUE_LEN
+ *****************************************/
+
+class P11AttrValueLen : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrValueLen(OSObject* inobject, CK_ULONG inchecks = 0) : P11Attribute(inobject) { type = CKA_VALUE_LEN; size = sizeof(CK_ULONG); checks = ck2|ck3|inchecks; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_WRAP_TEMPLATE
+ *****************************************/
+
+class P11AttrWrapTemplate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrWrapTemplate(OSObject* inobject) : P11Attribute(inobject) { type = CKA_WRAP_TEMPLATE; checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_UNWRAP_TEMPLATE
+ *****************************************/
+
+class P11AttrUnwrapTemplate : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrUnwrapTemplate(OSObject* inobject) : P11Attribute(inobject) { type = CKA_UNWRAP_TEMPLATE; checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+/*****************************************
+ * CKA_ALLOWED_MECHANISMS
+ *****************************************/
+
+class P11AttrAllowedMechanisms : public P11Attribute
+{
+public:
+       // Constructor
+       P11AttrAllowedMechanisms(OSObject* inobject) : P11Attribute(inobject) { type = CKA_ALLOWED_MECHANISMS; checks = 0; }
+
+protected:
+       // Set the default value of the attribute
+       virtual bool setDefault();
+
+       // Update the value if allowed
+       virtual CK_RV updateAttr(Token *token, bool isPrivate, CK_VOID_PTR pValue, CK_ULONG ulValueLen, int op);
+};
+
+#endif // !_SOFTHSM_V2_P11ATTRIBUTES_H
diff --git a/SoftHSMv2/src/lib/P11Objects.cpp b/SoftHSMv2/src/lib/P11Objects.cpp
new file mode 100644 (file)
index 0000000..c58d4ec
--- /dev/null
@@ -0,0 +1,1807 @@
+/*
+ * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ P11Objects.cpp
+
+ This class respresent a PKCS#11 object
+ *****************************************************************************/
+
+#include "config.h"
+#include "P11Objects.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+// Constructor
+P11Object::P11Object()
+{
+       initialized = false;
+       osobject = NULL;
+}
+
+// Destructor
+P11Object::~P11Object()
+{
+       std::map<CK_ATTRIBUTE_TYPE, P11Attribute*> cleanUp = attributes;
+       attributes.clear();
+
+       for (std::map<CK_ATTRIBUTE_TYPE, P11Attribute*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               if (i->second == NULL)
+               {
+                       continue;
+               }
+
+               delete i->second;
+               i->second = NULL;
+       }
+}
+
+// Add attributes
+bool P11Object::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       osobject = inobject;
+
+       // Create attributes
+       P11Attribute* attrClass = new P11AttrClass(osobject);
+       P11Attribute* attrToken = new P11AttrToken(osobject);
+       P11Attribute* attrPrivate = new P11AttrPrivate(osobject);
+       P11Attribute* attrModifiable = new P11AttrModifiable(osobject);
+       P11Attribute* attrLabel = new P11AttrLabel(osobject);
+       P11Attribute* attrCopyable = new P11AttrCopyable(osobject);
+       P11Attribute* attrDestroyable = new P11AttrDestroyable(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrClass->init() ||
+               !attrToken->init() ||
+               !attrPrivate->init() ||
+               !attrModifiable->init() ||
+               !attrLabel->init() ||
+               !attrCopyable->init() ||
+               !attrDestroyable->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrClass;
+               delete attrToken;
+               delete attrPrivate;
+               delete attrModifiable;
+               delete attrLabel;
+               delete attrCopyable;
+               delete attrDestroyable;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrClass->getType()] = attrClass;
+       attributes[attrToken->getType()] = attrToken;
+       attributes[attrPrivate->getType()] = attrPrivate;
+       attributes[attrModifiable->getType()] = attrModifiable;
+       attributes[attrLabel->getType()] = attrLabel;
+       attributes[attrCopyable->getType()] = attrCopyable;
+       attributes[attrDestroyable->getType()] = attrDestroyable;
+
+       initialized = true;
+       return true;
+}
+
+CK_RV P11Object::loadTemplate(Token *token, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
+{
+       bool isPrivate = this->isPrivate();
+
+       // [PKCS#11 v2.40, C_GetAttributeValue]
+       // 1. If the specified attribute (i.e., the attribute specified by the
+       //    type field) for the object cannot be revealed because the object
+       //    is sensitive or unextractable, then the ulValueLen field in that
+       //    triple is modified to hold the value CK_UNAVAILABLE_INFORMATION.
+       //
+       // 2. Otherwise, if the specified value for the object is invalid (the
+       //    object does not possess such an attribute), then the ulValueLen
+       //    field in that triple is modified to hold the value
+       //    CK_UNAVAILABLE_INFORMATION.
+       //
+       // 3. Otherwise, if the pValue field has the value NULL_PTR, then the
+       //    ulValueLen field is modified to hold the exact length of the
+       //    specified attribute for the object.
+       //
+       // 4. Otherwise, if the length specified in ulValueLen is large enough
+       //    to hold the value of the specified attribute for the object,
+       //    then that attribute is copied into the buffer located at pValue,
+       //    and the ulValueLen field is modified to hold the exact length of
+       //    the attribute.
+       //
+       // 5. Otherwise, the ulValueLen field is modified to hold the value
+       //    CK_UNAVAILABLE_INFORMATION.
+
+       bool invalid = false, sensitive = false, buffer_too_small = false;
+
+       // If case 3 or 4 applies to all the requested attributes, then the call will return CKR_OK.
+       for (CK_ULONG i = 0; i < ulAttributeCount; ++i)
+       {
+               P11Attribute* attr = attributes[pTemplate[i].type];
+
+               // case 2 of the attribute checks
+               if (attr == NULL) {
+                       pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION;
+                       // If case 2 applies to any of the requested attributes, then the call should
+                       // return the value CKR_ATTRIBUTE_TYPE_INVALID.
+                       invalid = true;
+                       continue;
+               }
+
+               // case 1,3,4 and 5 of the attribute checks are done while retrieving the attribute itself.
+               CK_RV retrieve_rv = attr->retrieve(token, isPrivate, pTemplate[i].pValue, &pTemplate[i].ulValueLen);
+               if (retrieve_rv == CKR_ATTRIBUTE_SENSITIVE) {
+                       // If case 1 applies to any of the requested attributes, then the call should
+                       // return the value CKR_ATTRIBUTE_SENSITIVE.
+                       sensitive = true;
+               } else if (retrieve_rv == CKR_BUFFER_TOO_SMALL) {
+                       // If case 5 applies to any of the requested attributes, then the call should
+                       // return the value CKR_BUFFER_TOO_SMALL.
+                       buffer_too_small = true;
+               } else if (retrieve_rv != CKR_OK) {
+                   return CKR_GENERAL_ERROR;
+               }
+
+       }
+
+       // As usual if more than one of these error codes is applicable, Cryptoki may
+       // return any of them. Only if none of them applies to any of the requested
+       // attributes will CKR_OK be returned. We choose to return the errors in
+       // the following priority, which is probably the most useful order.
+       if (sensitive)
+               return CKR_ATTRIBUTE_SENSITIVE;
+       if (invalid)
+               return CKR_ATTRIBUTE_TYPE_INVALID;
+       if (buffer_too_small)
+               return CKR_BUFFER_TOO_SMALL;
+       return CKR_OK;
+}
+
+// Save template
+CK_RV P11Object::saveTemplate(Token *token, bool isPrivate, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, int op)
+{
+       if (osobject == NULL)
+               return CKR_GENERAL_ERROR;
+       if (osobject->startTransaction() == false)
+               return CKR_GENERAL_ERROR;
+
+       if (op == OBJECT_OP_SET)
+       {
+               if (!isModifiable())
+               {
+                       osobject->abortTransaction();
+                       return CKR_ACTION_PROHIBITED;
+               }
+       }
+
+       // [PKCS#11 v2.40, 4.1.3 Copying objects] OBJECT_OP_COPY
+       //    If the CKA_COPYABLE attribute of the object to be copied is set
+       //    to CK_FALSE, C_CopyObject returns CKR_ACTION_PROHIBITED.
+       if (op == OBJECT_OP_COPY)
+       {
+               if (!isCopyable())
+               {
+                       osobject->abortTransaction();
+                       return CKR_ACTION_PROHIBITED;
+               }
+       }
+
+       for (CK_ULONG i = 0; i < ulAttributeCount; i++)
+       {
+               // [PKCS#11 v2.40, 4.1.1 Creating objects] OBJECT_OP_CREATE | OBJECT_OP_SET | OBJECT_OP_COPY
+               //    1. If the supplied template specifies a value for an invalid attribute, then the attempt
+               //    should fail with the error code CKR_ATTRIBUTE_TYPE_INVALID. An attribute
+               //    is valid if it is either one of the attributes described in the Cryptoki specification or an
+               //    additional vendor-specific attribute supported by the library and token.
+               P11Attribute* attr = attributes[pTemplate[i].type];
+
+               if (attr == NULL)
+               {
+                       osobject->abortTransaction();
+                       return CKR_ATTRIBUTE_TYPE_INVALID;
+               }
+
+               // Additonal checks are done while updating the attributes themselves.
+               CK_RV rv = attr->update(token,isPrivate, pTemplate[i].pValue, pTemplate[i].ulValueLen, op);
+               if (rv != CKR_OK)
+               {
+                       osobject->abortTransaction();
+                       return rv;
+               }
+       }
+
+       // [PKCS#11 v2.40, 4.1.1 Creating objects]
+       //    4. If the attribute values in the supplied template, together with any default attribute
+       //    values and any attribute values contributed to the object by the object-creation
+       //    function itself, are insufficient to fully specify the object to create, then the attempt
+       //    should fail with the error code CKR_TEMPLATE_INCOMPLETE.
+
+       // All attributes that have to be specified are marked as such in the specification.
+       // The following checks are relevant here:
+       for (std::map<CK_ATTRIBUTE_TYPE, P11Attribute*>::iterator i = attributes.begin(); i != attributes.end(); i++)
+       {
+               CK_ULONG checks = i->second->getChecks();
+
+               //  ck1  MUST be specified when object is created with C_CreateObject.
+               //  ck3  MUST be specified when object is generated with C_GenerateKey or C_GenerateKeyPair.
+               //  ck5  MUST be specified when object is unwrapped with C_UnwrapKey.
+               if (((checks & P11Attribute::ck1) == P11Attribute::ck1 && op == OBJECT_OP_CREATE) ||
+                   ((checks & P11Attribute::ck3) == P11Attribute::ck3 && op == OBJECT_OP_GENERATE) ||
+                   ((checks & P11Attribute::ck5) == P11Attribute::ck5 && op == OBJECT_OP_UNWRAP))
+               {
+                       bool isSpecified = false;
+
+                       for (CK_ULONG n = 0; n < ulAttributeCount; n++)
+                       {
+                               if (i->first == pTemplate[n].type)
+                               {
+                                       isSpecified = true;
+                                       break;
+                               }
+                       }
+
+                       if (!isSpecified)
+                       {
+                               ERROR_MSG("Mandatory attribute (0x%08X) was not specified in template", (unsigned int)i->first);
+
+                               return CKR_TEMPLATE_INCOMPLETE;
+                       }
+               }
+       }
+
+       // [PKCS#11 v2.40, 4.1.1 Creating objects]
+       //    5. If the attribute values in the supplied template, together with any default attribute
+       //    values and any attribute values contributed to the object by the object-creation
+       //    function itself, are inconsistent, then the attempt should fail with the error code
+       //    CKR_TEMPLATE_INCONSISTENT. A set of attribute values is inconsistent if not
+       //    all of its members can be satisfied simultaneously by the token, although each value
+       //    individually is valid in Cryptoki. One example of an inconsistent template would be
+       //    using a template which specifies two different values for the same attribute. Another
+       //    example would be trying to create a secret key object with an attribute which is
+       //    appropriate for various types of public keys or private keys, but not for secret keys.
+       //    A final example would be a template with an attribute that violates some token
+       //    specific requirement. Note that this final example of an inconsistent template is
+       //    token-dependent—on a different token, such a template might not be inconsistent.
+
+       if (osobject->commitTransaction() == false)
+       {
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+bool P11Object::isPrivate()
+{
+       // Get the CKA_PRIVATE attribute, when the attribute is
+       // not present return the default value which we have
+       // chosen to be CK_FALSE.
+       if (!osobject->attributeExists(CKA_PRIVATE)) return false;
+
+       return osobject->getBooleanValue(CKA_PRIVATE, false);
+}
+
+bool P11Object::isCopyable()
+{
+       // Get the CKA_COPYABLE attribute, when the attribute is not
+       // present return the default value which is CK_TRUE.
+       if (!osobject->attributeExists(CKA_COPYABLE)) return true;
+
+       return osobject->getBooleanValue(CKA_COPYABLE, true);
+}
+
+bool P11Object::isModifiable()
+{
+       // Get the CKA_MODIFIABLE attribute, when the attribute is
+       // not present return the default value which is CK_TRUE.
+       if (!osobject->attributeExists(CKA_MODIFIABLE)) return true;
+
+       return osobject->getBooleanValue(CKA_MODIFIABLE, true);
+}
+
+// Constructor
+P11DataObj::P11DataObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DataObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Set default values for attributes that will be introduced in the parent
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_DATA) {
+               OSAttribute setClass((unsigned long)CKO_DATA);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+
+       // Create parent
+       if (!P11Object::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrApplication = new P11AttrApplication(osobject);
+       P11Attribute* attrObjectID = new P11AttrObjectID(osobject);
+       // NOTE: There is no mention in the PKCS#11 v2.40 spec that for a Data
+       //  Object the CKA_VALUE attribute may be modified after creation!
+       //  Therefore we assume it is not allowed to change the CKA_VALUE
+       //  attribute of a Data Object.
+       P11Attribute* attrValue = new P11AttrValue(osobject,0);
+
+       // Initialize the attributes
+       if
+       (
+               !attrApplication->init() ||
+               !attrObjectID->init() ||
+               !attrValue->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrApplication;
+               delete attrObjectID;
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrApplication->getType()] = attrApplication;
+       attributes[attrObjectID->getType()] = attrObjectID;
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11CertificateObj::P11CertificateObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11CertificateObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Set default values for attributes that will be introduced in the parent
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_CERTIFICATE) {
+               OSAttribute setClass((unsigned long)CKO_CERTIFICATE);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+       // Make certificates public
+       if (!inobject->attributeExists(CKA_PRIVATE)) {
+               OSAttribute setPrivate(false);
+               inobject->setAttribute(CKA_PRIVATE, setPrivate);
+       }
+
+       // Create parent
+       if (!P11Object::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrCertificateType = new P11AttrCertificateType(osobject);
+       P11Attribute* attrTrusted = new P11AttrTrusted(osobject);
+       P11Attribute* attrCertificateCategory = new P11AttrCertificateCategory(osobject);
+       // NOTE: Because these attributes are used in a certificate object
+       //  where the CKA_VALUE containing the certificate data is not
+       //  modifiable, we assume that this attribute is also not modifiable.
+       //  There is also no explicit mention of these attributes being modifiable.
+       P11Attribute* attrCheckValue = new P11AttrCheckValue(osobject, 0);
+       P11Attribute* attrStartDate = new P11AttrStartDate(osobject,0);
+       P11Attribute* attrEndDate = new P11AttrEndDate(osobject,0);
+       // TODO: CKA_PUBLIC_KEY_INFO is accepted, but we do not calculate it.
+       P11Attribute* attrPublicKeyInfo = new P11AttrPublicKeyInfo(osobject,0);
+
+       // Initialize the attributes
+       if
+       (
+               !attrCertificateType->init() ||
+               !attrTrusted->init() ||
+               !attrCertificateCategory->init() ||
+               !attrCheckValue->init() ||
+               !attrStartDate->init() ||
+               !attrEndDate->init() ||
+               !attrPublicKeyInfo->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrCertificateType;
+               delete attrTrusted;
+               delete attrCertificateCategory;
+               delete attrCheckValue;
+               delete attrStartDate;
+               delete attrEndDate;
+               delete attrPublicKeyInfo;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrCertificateType->getType()] = attrCertificateType;
+       attributes[attrTrusted->getType()] = attrTrusted;
+       attributes[attrCertificateCategory->getType()] = attrCertificateCategory;
+       attributes[attrCheckValue->getType()] = attrCheckValue;
+       attributes[attrStartDate->getType()] = attrStartDate;
+       attributes[attrEndDate->getType()] = attrEndDate;
+       attributes[attrPublicKeyInfo->getType()] = attrPublicKeyInfo;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11X509CertificateObj::P11X509CertificateObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11X509CertificateObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Set default values for attributes that will be introduced in the parent
+       if (!inobject->attributeExists(CKA_CERTIFICATE_TYPE) || inobject->getUnsignedLongValue(CKA_CERTIFICATE_TYPE, CKC_VENDOR_DEFINED) != CKC_X_509) {
+               OSAttribute setCertType((unsigned long)CKC_X_509);
+               inobject->setAttribute(CKA_CERTIFICATE_TYPE, setCertType);
+       }
+
+       // Create parent
+       if (!P11CertificateObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrSubject = new P11AttrSubject(osobject,P11Attribute::ck1);
+       P11Attribute* attrID = new P11AttrID(osobject);
+       P11Attribute* attrIssuer = new P11AttrIssuer(osobject);
+       P11Attribute* attrSerialNumber = new P11AttrSerialNumber(osobject);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck14);
+       P11Attribute* attrURL = new P11AttrURL(osobject);
+       P11Attribute* attrHashOfSubjectPublicKey = new P11AttrHashOfSubjectPublicKey(osobject);
+       P11Attribute* attrHashOfIssuerPublicKey = new P11AttrHashOfIssuerPublicKey(osobject);
+       P11Attribute* attrJavaMidpSecurityDomain = new P11AttrJavaMidpSecurityDomain(osobject);
+       P11Attribute* attrNameHashAlgorithm = new P11AttrNameHashAlgorithm(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrSubject->init() ||
+               !attrID->init() ||
+               !attrIssuer->init() ||
+               !attrSerialNumber->init() ||
+               !attrValue->init() ||
+               !attrURL->init() ||
+               !attrHashOfSubjectPublicKey->init() ||
+               !attrHashOfIssuerPublicKey->init() ||
+               !attrJavaMidpSecurityDomain->init() ||
+               !attrNameHashAlgorithm->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrSubject;
+               delete attrID;
+               delete attrIssuer;
+               delete attrSerialNumber;
+               delete attrValue;
+               delete attrURL;
+               delete attrHashOfSubjectPublicKey;
+               delete attrHashOfIssuerPublicKey;
+               delete attrJavaMidpSecurityDomain;
+               delete attrNameHashAlgorithm;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrSubject->getType()] = attrSubject;
+       attributes[attrID->getType()] = attrID;
+       attributes[attrIssuer->getType()] = attrIssuer;
+       attributes[attrSerialNumber->getType()] = attrSerialNumber;
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrURL->getType()] = attrURL;
+       attributes[attrHashOfSubjectPublicKey->getType()] = attrHashOfSubjectPublicKey;
+       attributes[attrHashOfIssuerPublicKey->getType()] = attrHashOfIssuerPublicKey;
+       attributes[attrJavaMidpSecurityDomain->getType()] = attrJavaMidpSecurityDomain;
+       attributes[attrNameHashAlgorithm->getType()] = attrNameHashAlgorithm;
+
+       return true;
+}
+
+// Constructor
+P11OpenPGPPublicKeyObj::P11OpenPGPPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11OpenPGPPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Set default values for attributes that will be introduced in the parent
+       if (!inobject->attributeExists(CKA_CERTIFICATE_TYPE) || inobject->getUnsignedLongValue(CKA_CERTIFICATE_TYPE, CKC_VENDOR_DEFINED) != CKC_OPENPGP) {
+               OSAttribute setCertType((unsigned long)CKC_OPENPGP);
+               inobject->setAttribute(CKA_CERTIFICATE_TYPE, setCertType);
+       }
+
+       // Create parent
+       if (!P11CertificateObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrSubject = new P11AttrSubject(osobject,P11Attribute::ck1);
+       P11Attribute* attrID = new P11AttrID(osobject);
+       P11Attribute* attrIssuer = new P11AttrIssuer(osobject);
+       P11Attribute* attrSerialNumber = new P11AttrSerialNumber(osobject);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck14);
+       P11Attribute* attrURL = new P11AttrURL(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrSubject->init() ||
+               !attrID->init() ||
+               !attrIssuer->init() ||
+               !attrSerialNumber->init() ||
+               !attrValue->init() ||
+               !attrURL->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrSubject;
+               delete attrID;
+               delete attrIssuer;
+               delete attrSerialNumber;
+               delete attrValue;
+               delete attrURL;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrSubject->getType()] = attrSubject;
+       attributes[attrID->getType()] = attrID;
+       attributes[attrIssuer->getType()] = attrIssuer;
+       attributes[attrSerialNumber->getType()] = attrSerialNumber;
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrURL->getType()] = attrURL;
+
+       return true;
+}
+
+// Constructor
+P11KeyObj::P11KeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11KeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Create parent
+       if (!P11Object::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrKeyType = new P11AttrKeyType(osobject,P11Attribute::ck5);
+       P11Attribute* attrID = new P11AttrID(osobject);
+       P11Attribute* attrStartDate = new P11AttrStartDate(osobject,P11Attribute::ck8);
+       P11Attribute* attrEndDate = new P11AttrEndDate(osobject,P11Attribute::ck8);
+       P11Attribute* attrDerive = new P11AttrDerive(osobject);
+       P11Attribute* attrLocal = new P11AttrLocal(osobject,P11Attribute::ck6);
+       P11Attribute* attrKeyGenMechanism = new P11AttrKeyGenMechanism(osobject);
+       P11Attribute* attrAllowedMechanisms = new P11AttrAllowedMechanisms(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrKeyType->init() ||
+               !attrID->init() ||
+               !attrStartDate->init() ||
+               !attrEndDate->init() ||
+               !attrDerive->init() ||
+               !attrLocal->init() ||
+               !attrKeyGenMechanism->init() ||
+               !attrAllowedMechanisms->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrKeyType;
+               delete attrID;
+               delete attrStartDate;
+               delete attrEndDate;
+               delete attrDerive;
+               delete attrLocal;
+               delete attrKeyGenMechanism;
+               delete attrAllowedMechanisms;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrKeyType->getType()] = attrKeyType;
+       attributes[attrID->getType()] = attrID;
+       attributes[attrStartDate->getType()] = attrStartDate;
+       attributes[attrEndDate->getType()] = attrEndDate;
+       attributes[attrDerive->getType()] = attrDerive;
+       attributes[attrLocal->getType()] = attrLocal;
+       attributes[attrKeyGenMechanism->getType()] = attrKeyGenMechanism;
+       attributes[attrAllowedMechanisms->getType()] = attrAllowedMechanisms;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11PublicKeyObj::P11PublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11PublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       // Set default values for attributes that will be introduced in the parent
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PUBLIC_KEY) {
+               OSAttribute setClass((unsigned long)CKO_PUBLIC_KEY);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+       // Make public keys public
+       if (!inobject->attributeExists(CKA_PRIVATE)) {
+               OSAttribute setPrivate(false);
+               inobject->setAttribute(CKA_PRIVATE, setPrivate);
+       }
+
+       // Create parent
+       if (!P11KeyObj::init(inobject)) return false;
+
+       if (initialized) return true;
+
+       // Create attributes
+       P11Attribute* attrSubject = new P11AttrSubject(osobject,P11Attribute::ck8);
+       P11Attribute* attrEncrypt = new P11AttrEncrypt(osobject);
+       P11Attribute* attrVerify = new P11AttrVerify(osobject);
+       P11Attribute* attrVerifyRecover = new P11AttrVerifyRecover(osobject);
+       P11Attribute* attrWrap = new P11AttrWrap(osobject);
+       P11Attribute* attrTrusted = new P11AttrTrusted(osobject);
+       P11Attribute* attrWrapTemplate = new P11AttrWrapTemplate(osobject);
+       // TODO: CKA_PUBLIC_KEY_INFO is accepted, but we do not calculate it
+       P11Attribute* attrPublicKeyInfo = new P11AttrPublicKeyInfo(osobject,0);
+
+       // Initialize the attributes
+       if
+       (
+               !attrSubject->init() ||
+               !attrEncrypt->init() ||
+               !attrVerify->init() ||
+               !attrVerifyRecover->init() ||
+               !attrWrap->init() ||
+               !attrTrusted->init() ||
+               !attrWrapTemplate->init() ||
+               !attrPublicKeyInfo->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrSubject;
+               delete attrEncrypt;
+               delete attrVerify;
+               delete attrVerifyRecover;
+               delete attrWrap;
+               delete attrTrusted;
+               delete attrWrapTemplate;
+               delete attrPublicKeyInfo;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrSubject->getType()] = attrSubject;
+       attributes[attrEncrypt->getType()] = attrEncrypt;
+       attributes[attrVerify->getType()] = attrVerify;
+       attributes[attrVerifyRecover->getType()] = attrVerifyRecover;
+       attributes[attrWrap->getType()] = attrWrap;
+       attributes[attrTrusted->getType()] = attrTrusted;
+       attributes[attrWrapTemplate->getType()] = attrWrapTemplate;
+       attributes[attrPublicKeyInfo->getType()] = attrPublicKeyInfo;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11RSAPublicKeyObj::P11RSAPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11RSAPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) {
+               OSAttribute setKeyType((unsigned long)CKK_RSA);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PublicKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrModulus = new P11AttrModulus(osobject);
+       P11Attribute* attrModulusBits = new P11AttrModulusBits(osobject);
+       P11Attribute* attrPublicExponent = new P11AttrPublicExponent(osobject,P11Attribute::ck1);
+
+       // Initialize the attributes
+       if
+       (
+               !attrModulus->init() ||
+               !attrModulusBits->init() ||
+               !attrPublicExponent->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrModulus;
+               delete attrModulusBits;
+               delete attrPublicExponent;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrModulus->getType()] = attrModulus;
+       attributes[attrModulusBits->getType()] = attrModulusBits;
+       attributes[attrPublicExponent->getType()] = attrPublicExponent;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DSAPublicKeyObj::P11DSAPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DSAPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DSA) {
+               OSAttribute setKeyType((unsigned long)CKK_DSA);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PublicKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck3);
+       P11Attribute* attrSubPrime = new P11AttrSubPrime(osobject,P11Attribute::ck3);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck3);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrSubPrime->init() ||
+               !attrBase->init() ||
+               !attrValue->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrSubPrime;
+               delete attrBase;
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrSubPrime->getType()] = attrSubPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11ECPublicKeyObj::P11ECPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11ECPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_EC) {
+               OSAttribute setKeyType((unsigned long)CKK_EC);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PublicKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrEcParams = new P11AttrEcParams(osobject,P11Attribute::ck3);
+       P11Attribute* attrEcPoint = new P11AttrEcPoint(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrEcParams->init() ||
+               !attrEcPoint->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrEcParams;
+               delete attrEcPoint;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrEcParams->getType()] = attrEcParams;
+       attributes[attrEcPoint->getType()] = attrEcPoint;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DHPublicKeyObj::P11DHPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DHPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DH) {
+               OSAttribute setKeyType((unsigned long)CKK_DH);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PublicKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck3);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck3);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrBase->init() ||
+               !attrValue->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrBase;
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11GOSTPublicKeyObj::P11GOSTPublicKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11GOSTPublicKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_GOSTR3410) {
+               OSAttribute setKeyType((unsigned long)CKK_GOSTR3410);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PublicKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4);
+       P11Attribute* attrGostR3410Params = new P11AttrGostR3410Params(osobject,P11Attribute::ck3);
+       P11Attribute* attrGostR3411Params = new P11AttrGostR3411Params(osobject,P11Attribute::ck3);
+       P11Attribute* attrGost28147Params = new P11AttrGost28147Params(osobject,P11Attribute::ck8);
+
+       // Initialize the attributes
+       if
+       (
+               !attrValue->init() ||
+               !attrGostR3410Params->init() ||
+               !attrGostR3411Params->init() ||
+               !attrGost28147Params->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               delete attrGostR3410Params;
+               delete attrGostR3411Params;
+               delete attrGost28147Params;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrGostR3410Params->getType()] = attrGostR3410Params;
+       attributes[attrGostR3411Params->getType()] = attrGostR3411Params;
+       attributes[attrGost28147Params->getType()] = attrGost28147Params;
+
+       initialized = true;
+       return true;
+}
+
+//constructor
+P11PrivateKeyObj::P11PrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11PrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY) {
+               OSAttribute setClass((unsigned long)CKO_PRIVATE_KEY);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+
+       // Create parent
+       if (!P11KeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrSubject = new P11AttrSubject(osobject,P11Attribute::ck8);
+       P11Attribute* attrSensitive = new P11AttrSensitive(osobject);
+       P11Attribute* attrDecrypt = new P11AttrDecrypt(osobject);
+       P11Attribute* attrSign = new P11AttrSign(osobject);
+       P11Attribute* attrSignRecover = new P11AttrSignRecover(osobject);
+       P11Attribute* attrUnwrap = new P11AttrUnwrap(osobject);
+       P11Attribute* attrExtractable = new P11AttrExtractable(osobject);
+       P11Attribute* attrAlwaysSensitive = new P11AttrAlwaysSensitive(osobject);
+       P11Attribute* attrNeverExtractable = new P11AttrNeverExtractable(osobject);
+       P11Attribute* attrWrapWithTrusted = new P11AttrWrapWithTrusted(osobject);
+       P11Attribute* attrUnwrapTemplate = new P11AttrUnwrapTemplate(osobject);
+       // TODO: CKA_ALWAYS_AUTHENTICATE is accepted, but we do not use it
+       P11Attribute* attrAlwaysAuthenticate = new P11AttrAlwaysAuthenticate(osobject);
+       // TODO: CKA_PUBLIC_KEY_INFO is accepted, but we do not calculate it
+       P11Attribute* attrPublicKeyInfo = new P11AttrPublicKeyInfo(osobject,P11Attribute::ck8);
+
+       // Initialize the attributes
+       if
+       (
+               !attrSubject->init() ||
+               !attrSensitive->init() ||
+               !attrDecrypt->init() ||
+               !attrSign->init() ||
+               !attrSignRecover->init() ||
+               !attrUnwrap->init() ||
+               !attrExtractable->init() ||
+               !attrAlwaysSensitive->init() ||
+               !attrNeverExtractable->init() ||
+               !attrWrapWithTrusted->init() ||
+               !attrUnwrapTemplate->init() ||
+               !attrAlwaysAuthenticate->init() ||
+               !attrPublicKeyInfo->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrSubject;
+               delete attrSensitive;
+               delete attrDecrypt;
+               delete attrSign;
+               delete attrSignRecover;
+               delete attrUnwrap;
+               delete attrExtractable;
+               delete attrAlwaysSensitive;
+               delete attrNeverExtractable;
+               delete attrWrapWithTrusted;
+               delete attrUnwrapTemplate;
+               delete attrAlwaysAuthenticate;
+               delete attrPublicKeyInfo;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrSubject->getType()] = attrSubject;
+       attributes[attrSensitive->getType()] = attrSensitive;
+       attributes[attrDecrypt->getType()] = attrDecrypt;
+       attributes[attrSign->getType()] = attrSign;
+       attributes[attrSignRecover->getType()] = attrSignRecover;
+       attributes[attrUnwrap->getType()] = attrUnwrap;
+       attributes[attrExtractable->getType()] = attrExtractable;
+       attributes[attrAlwaysSensitive->getType()] = attrAlwaysSensitive;
+       attributes[attrNeverExtractable->getType()] = attrNeverExtractable;
+       attributes[attrWrapWithTrusted->getType()] = attrWrapWithTrusted;
+       attributes[attrUnwrapTemplate->getType()] = attrUnwrapTemplate;
+       attributes[attrAlwaysAuthenticate->getType()] = attrAlwaysAuthenticate;
+       attributes[attrPublicKeyInfo->getType()] = attrPublicKeyInfo;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11RSAPrivateKeyObj::P11RSAPrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11RSAPrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) {
+               OSAttribute setKeyType((unsigned long)CKK_RSA);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PrivateKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrModulus = new P11AttrModulus(osobject,P11Attribute::ck6);
+       P11Attribute* attrPublicExponent = new P11AttrPublicExponent(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrPrivateExponent = new P11AttrPrivateExponent(osobject);
+       P11Attribute* attrPrime1 = new P11AttrPrime1(osobject);
+       P11Attribute* attrPrime2 = new P11AttrPrime2(osobject);
+       P11Attribute* attrExponent1 = new P11AttrExponent1(osobject);
+       P11Attribute* attrExponent2 = new P11AttrExponent2(osobject);
+       P11Attribute* attrCoefficient = new P11AttrCoefficient(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrModulus->init() ||
+               !attrPublicExponent->init() ||
+               !attrPrivateExponent->init() ||
+               !attrPrime1->init() ||
+               !attrPrime2->init() ||
+               !attrExponent1->init() ||
+               !attrExponent2->init() ||
+               !attrCoefficient->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrModulus;
+               delete attrPublicExponent;
+               delete attrPrivateExponent;
+               delete attrPrime1;
+               delete attrPrime2;
+               delete attrExponent1;
+               delete attrExponent2;
+               delete attrCoefficient;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrModulus->getType()] = attrModulus;
+       attributes[attrPublicExponent->getType()] = attrPublicExponent;
+       attributes[attrPrivateExponent->getType()] = attrPrivateExponent;
+       attributes[attrPrime1->getType()] = attrPrime1;
+       attributes[attrPrime2->getType()] = attrPrime2;
+       attributes[attrExponent1->getType()] = attrExponent1;
+       attributes[attrExponent2->getType()] = attrExponent2;
+       attributes[attrCoefficient->getType()] = attrCoefficient;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DSAPrivateKeyObj::P11DSAPrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DSAPrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DSA) {
+               OSAttribute setKeyType((unsigned long)CKK_DSA);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PrivateKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrSubPrime = new P11AttrSubPrime(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrSubPrime->init() ||
+               !attrBase->init() ||
+               !attrValue->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrSubPrime;
+               delete attrBase;
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrSubPrime->getType()] = attrSubPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11ECPrivateKeyObj::P11ECPrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11ECPrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_EC) {
+               OSAttribute setKeyType((unsigned long)CKK_EC);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PrivateKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrEcParams = new P11AttrEcParams(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+
+       // Initialize the attributes
+       if
+       (
+               !attrEcParams->init() ||
+               !attrValue->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrEcParams;
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrEcParams->getType()] = attrEcParams;
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DHPrivateKeyObj::P11DHPrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DHPrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DH) {
+               OSAttribute setKeyType((unsigned long)CKK_DH);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PrivateKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+       P11Attribute* attrValueBits = new P11AttrValueBits(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrBase->init() ||
+               !attrValue->init() ||
+               !attrValueBits->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrBase;
+               delete attrValue;
+               delete attrValueBits;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrValueBits->getType()] = attrValueBits;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11GOSTPrivateKeyObj::P11GOSTPrivateKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11GOSTPrivateKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_GOSTR3410) {
+               OSAttribute setKeyType((unsigned long)CKK_GOSTR3410);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11PrivateKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+       P11Attribute* attrGostR3410Params = new P11AttrGostR3410Params(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrGostR3411Params = new P11AttrGostR3411Params(osobject,P11Attribute::ck4|P11Attribute::ck6);
+       P11Attribute* attrGost28147Params = new P11AttrGost28147Params(osobject,P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck8);
+
+       // Initialize the attributes
+       if
+       (
+               !attrValue->init() ||
+               !attrGostR3410Params->init() ||
+               !attrGostR3411Params->init() ||
+               !attrGost28147Params->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               delete attrGostR3410Params;
+               delete attrGostR3411Params;
+               delete attrGost28147Params;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrGostR3410Params->getType()] = attrGostR3410Params;
+       attributes[attrGostR3411Params->getType()] = attrGostR3411Params;
+       attributes[attrGost28147Params->getType()] = attrGost28147Params;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11SecretKeyObj::P11SecretKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11SecretKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY) {
+               OSAttribute setClass((unsigned long)CKO_SECRET_KEY);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+
+       // Create parent
+       if (!P11KeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrSensitive = new P11AttrSensitive(osobject);
+       P11Attribute* attrEncrypt = new P11AttrEncrypt(osobject);
+       P11Attribute* attrDecrypt = new P11AttrDecrypt(osobject);
+       P11Attribute* attrSign = new P11AttrSign(osobject);
+       P11Attribute* attrVerify = new P11AttrVerify(osobject);
+       P11Attribute* attrWrap = new P11AttrWrap(osobject);
+       P11Attribute* attrUnwrap = new P11AttrUnwrap(osobject);
+       P11Attribute* attrExtractable = new P11AttrExtractable(osobject);
+       P11Attribute* attrAlwaysSensitive = new P11AttrAlwaysSensitive(osobject);
+       P11Attribute* attrNeverExtractable = new P11AttrNeverExtractable(osobject);
+       P11Attribute* attrCheckValue = new P11AttrCheckValue(osobject, P11Attribute::ck8);
+       P11Attribute* attrWrapWithTrusted = new P11AttrWrapWithTrusted(osobject);
+       P11Attribute* attrTrusted = new P11AttrTrusted(osobject);
+       P11Attribute* attrWrapTemplate = new P11AttrWrapTemplate(osobject);
+       P11Attribute* attrUnwrapTemplate = new P11AttrUnwrapTemplate(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrSensitive->init() ||
+               !attrEncrypt->init() ||
+               !attrDecrypt->init() ||
+               !attrSign->init() ||
+               !attrVerify->init() ||
+               !attrWrap->init() ||
+               !attrUnwrap->init() ||
+               !attrExtractable->init() ||
+               !attrAlwaysSensitive->init() ||
+               !attrNeverExtractable->init() ||
+               !attrCheckValue->init() ||
+               !attrWrapWithTrusted->init() ||
+               !attrTrusted->init() ||
+               !attrWrapTemplate->init() ||
+               !attrUnwrapTemplate->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrSensitive;
+               delete attrEncrypt;
+               delete attrDecrypt;
+               delete attrSign;
+               delete attrVerify;
+               delete attrWrap;
+               delete attrUnwrap;
+               delete attrExtractable;
+               delete attrAlwaysSensitive;
+               delete attrNeverExtractable;
+               delete attrCheckValue;
+               delete attrWrapWithTrusted;
+               delete attrTrusted;
+               delete attrWrapTemplate;
+               delete attrUnwrapTemplate;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrSensitive->getType()] = attrSensitive;
+       attributes[attrEncrypt->getType()] = attrEncrypt;
+       attributes[attrDecrypt->getType()] = attrDecrypt;
+       attributes[attrSign->getType()] = attrSign;
+       attributes[attrVerify->getType()] = attrVerify;
+       attributes[attrWrap->getType()] = attrWrap;
+       attributes[attrUnwrap->getType()] = attrUnwrap;
+       attributes[attrExtractable->getType()] = attrExtractable;
+       attributes[attrAlwaysSensitive->getType()] = attrAlwaysSensitive;
+       attributes[attrNeverExtractable->getType()] = attrNeverExtractable;
+       attributes[attrCheckValue->getType()] = attrCheckValue;
+       attributes[attrWrapWithTrusted->getType()] = attrWrapWithTrusted;
+       attributes[attrTrusted->getType()] = attrTrusted;
+       attributes[attrWrapTemplate->getType()] = attrWrapTemplate;
+       attributes[attrUnwrapTemplate->getType()] = attrUnwrapTemplate;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11GenericSecretKeyObj::P11GenericSecretKeyObj()
+{
+       initialized = false;
+       keytype = CKK_VENDOR_DEFINED;
+}
+
+// Add attributes
+bool P11GenericSecretKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != keytype) {
+               OSAttribute setKeyType(keytype);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11SecretKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+       P11Attribute* attrValueLen = new P11AttrValueLen(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrValue->init() ||
+               !attrValueLen->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               delete attrValueLen;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrValueLen->getType()] = attrValueLen;
+
+       initialized = true;
+       return true;
+}
+
+// Set Key Type
+bool P11GenericSecretKeyObj::setKeyType(CK_KEY_TYPE inKeytype)
+{
+       if (!initialized)
+       {
+               keytype = inKeytype;
+               return true;
+       }
+       else
+               return false;
+}
+
+// Get Key Type
+CK_KEY_TYPE P11GenericSecretKeyObj::getKeyType()
+{
+       return keytype;
+}
+
+// Constructor
+P11AESSecretKeyObj::P11AESSecretKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11AESSecretKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) {
+               OSAttribute setKeyType((unsigned long)CKK_AES);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11SecretKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+       P11Attribute* attrValueLen = new P11AttrValueLen(osobject,P11Attribute::ck6);
+
+       // Initialize the attributes
+       if
+       (
+               !attrValue->init() ||
+               !attrValueLen->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               delete attrValueLen;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrValueLen->getType()] = attrValueLen;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DESSecretKeyObj::P11DESSecretKeyObj()
+{
+       initialized = false;
+       keytype = CKK_VENDOR_DEFINED;
+}
+
+// Add attributes
+bool P11DESSecretKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != keytype) {
+               OSAttribute setKeyType(keytype);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11SecretKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+
+       // Initialize the attributes
+       if (!attrValue->init())
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+
+       initialized = true;
+       return true;
+}
+
+// Set Key Type
+bool P11DESSecretKeyObj::setKeyType(CK_KEY_TYPE inKeytype)
+{
+       if (!initialized)
+       {
+               keytype = inKeytype;
+               return true;
+       }
+       else
+               return false;
+}
+
+// Get Key Type
+CK_KEY_TYPE P11DESSecretKeyObj::getKeyType()
+{
+       return keytype;
+}
+
+// Constructor
+P11GOSTSecretKeyObj::P11GOSTSecretKeyObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11GOSTSecretKeyObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_GOST28147) {
+               OSAttribute setKeyType((unsigned long)CKK_GOST28147);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11SecretKeyObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrValue = new P11AttrValue(osobject,P11Attribute::ck1|P11Attribute::ck4|P11Attribute::ck6|P11Attribute::ck7);
+       P11Attribute* attrGost28147Params = new P11AttrGost28147Params(osobject,P11Attribute::ck1|P11Attribute::ck3|P11Attribute::ck5);
+
+       // Initialize the attributes
+       if
+       (
+               !attrValue->init() ||
+               !attrGost28147Params->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrValue;
+               delete attrGost28147Params;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrValue->getType()] = attrValue;
+       attributes[attrGost28147Params->getType()] = attrGost28147Params;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DomainObj::P11DomainObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DomainObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_CLASS) || inobject->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_DOMAIN_PARAMETERS) {
+               OSAttribute setClass((unsigned long)CKO_DOMAIN_PARAMETERS);
+               inobject->setAttribute(CKA_CLASS, setClass);
+       }
+
+       // Create parent
+       if (!P11Object::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrKeyType = new P11AttrKeyType(osobject);
+       P11Attribute* attrLocal = new P11AttrLocal(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrKeyType->init() ||
+               !attrLocal->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrKeyType;
+               delete attrLocal;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrKeyType->getType()] = attrKeyType;
+       attributes[attrLocal->getType()] = attrLocal;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DSADomainObj::P11DSADomainObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DSADomainObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DSA) {
+               OSAttribute setKeyType((unsigned long)CKK_DSA);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11DomainObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck4);
+       P11Attribute* attrSubPrime = new P11AttrSubPrime(osobject,P11Attribute::ck4);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck4);
+       P11Attribute* attrPrimeBits = new P11AttrPrimeBits(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrSubPrime->init() ||
+               !attrBase->init() ||
+               !attrPrimeBits->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrSubPrime;
+               delete attrBase;
+               delete attrPrimeBits;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrSubPrime->getType()] = attrSubPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrPrimeBits->getType()] = attrPrimeBits;
+
+       initialized = true;
+       return true;
+}
+
+// Constructor
+P11DHDomainObj::P11DHDomainObj()
+{
+       initialized = false;
+}
+
+// Add attributes
+bool P11DHDomainObj::init(OSObject *inobject)
+{
+       if (initialized) return true;
+       if (inobject == NULL) return false;
+
+       if (!inobject->attributeExists(CKA_KEY_TYPE) || inobject->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DH) {
+               OSAttribute setKeyType((unsigned long)CKK_DH);
+               inobject->setAttribute(CKA_KEY_TYPE, setKeyType);
+       }
+
+       // Create parent
+       if (!P11DomainObj::init(inobject)) return false;
+
+       // Create attributes
+       P11Attribute* attrPrime = new P11AttrPrime(osobject,P11Attribute::ck4);
+       P11Attribute* attrBase = new P11AttrBase(osobject,P11Attribute::ck4);
+       P11Attribute* attrPrimeBits = new P11AttrPrimeBits(osobject);
+
+       // Initialize the attributes
+       if
+       (
+               !attrPrime->init() ||
+               !attrBase->init() ||
+               !attrPrimeBits->init()
+       )
+       {
+               ERROR_MSG("Could not initialize the attribute");
+               delete attrPrime;
+               delete attrBase;
+               delete attrPrimeBits;
+               return false;
+       }
+
+       // Add them to the map
+       attributes[attrPrime->getType()] = attrPrime;
+       attributes[attrBase->getType()] = attrBase;
+       attributes[attrPrimeBits->getType()] = attrPrimeBits;
+
+       initialized = true;
+       return true;
+}
diff --git a/SoftHSMv2/src/lib/P11Objects.h b/SoftHSMv2/src/lib/P11Objects.h
new file mode 100644 (file)
index 0000000..942a8c4
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ P11Objects.h
+
+ This class respresent a PKCS#11 object
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_P11OBJECTS_H
+#define _SOFTHSM_V2_P11OBJECTS_H
+
+#include "OSObject.h"
+#include "P11Attributes.h"
+#include "Token.h"
+#include "cryptoki.h"
+#include <map>
+
+class P11Object
+{
+public:
+       // Destructor
+       virtual ~P11Object();
+
+protected:
+       // Constructor
+       P11Object();
+
+       // The object
+       OSObject* osobject;
+
+       // The attributes
+       std::map<CK_ATTRIBUTE_TYPE, P11Attribute*> attributes;
+
+public:
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+
+public:
+       CK_RV loadTemplate(Token *token, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount);
+
+       // Save template
+       CK_RV saveTemplate(Token *token, bool isPrivate, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, int op);
+
+protected:
+       bool isPrivate();
+       bool isCopyable();
+       bool isModifiable();
+};
+
+class P11DataObj : public P11Object
+{
+public:
+       // Constructor
+       P11DataObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11CertificateObj : public P11Object
+{
+protected:
+       // Constructor
+       P11CertificateObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11X509CertificateObj : public P11CertificateObj
+{
+public:
+       // Constructor
+       P11X509CertificateObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11OpenPGPPublicKeyObj : public P11CertificateObj
+{
+public:
+       // Constructor
+       P11OpenPGPPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11KeyObj : public P11Object
+{
+protected:
+       // Constructor
+       P11KeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11PublicKeyObj : public P11KeyObj
+{
+protected:
+       // Constructor
+       P11PublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11RSAPublicKeyObj : public P11PublicKeyObj
+{
+public:
+       // Constructor
+       P11RSAPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DSAPublicKeyObj : public P11PublicKeyObj
+{
+public:
+       // Constructor
+       P11DSAPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11ECPublicKeyObj : public P11PublicKeyObj
+{
+public:
+       // Constructor
+       P11ECPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DHPublicKeyObj : public P11PublicKeyObj
+{
+public:
+       // Constructor
+       P11DHPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11GOSTPublicKeyObj : public P11PublicKeyObj
+{
+public:
+       // Constructor
+       P11GOSTPublicKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11PrivateKeyObj : public P11KeyObj
+{
+protected:
+       // Constructor
+       P11PrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11RSAPrivateKeyObj : public P11PrivateKeyObj
+{
+public:
+       // Constructor
+       P11RSAPrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DSAPrivateKeyObj : public P11PrivateKeyObj
+{
+public:
+       // Constructor
+       P11DSAPrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11ECPrivateKeyObj : public P11PrivateKeyObj
+{
+public:
+       // Constructor
+       P11ECPrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DHPrivateKeyObj : public P11PrivateKeyObj
+{
+public:
+       // Constructor
+       P11DHPrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11GOSTPrivateKeyObj : public P11PrivateKeyObj
+{
+public:
+       // Constructor
+       P11GOSTPrivateKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11SecretKeyObj : public P11KeyObj
+{
+protected:
+       // Constructor
+       P11SecretKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11GenericSecretKeyObj : public P11SecretKeyObj
+{
+public:
+       // Constructor
+       P11GenericSecretKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+       // Better than multiply subclasses
+       virtual bool setKeyType(CK_KEY_TYPE inKeytype);
+       virtual CK_KEY_TYPE getKeyType();
+
+protected:
+       bool initialized;
+       CK_KEY_TYPE keytype;
+};
+
+class P11AESSecretKeyObj : public P11SecretKeyObj
+{
+public:
+       // Constructor
+       P11AESSecretKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DESSecretKeyObj : public P11SecretKeyObj
+{
+public:
+       // Constructor
+       P11DESSecretKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+       // Better than multiply subclasses
+       virtual bool setKeyType(CK_KEY_TYPE inKeytype);
+       virtual CK_KEY_TYPE getKeyType();
+
+protected:
+       bool initialized;
+       CK_KEY_TYPE keytype;
+};
+
+class P11GOSTSecretKeyObj : public P11SecretKeyObj
+{
+public:
+       // Constructor
+       P11GOSTSecretKeyObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+
+protected:
+       bool initialized;
+};
+
+class P11DomainObj : public P11Object
+{
+protected:
+       // Constructor
+       P11DomainObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+       bool initialized;
+};
+
+class P11DSADomainObj : public P11DomainObj
+{
+public:
+       // Constructor
+       P11DSADomainObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+protected:
+       bool initialized;
+};
+
+class P11DHDomainObj : public P11DomainObj
+{
+public:
+       // Constructor
+       P11DHDomainObj();
+
+       // Add attributes
+       virtual bool init(OSObject *inobject);
+protected:
+       bool initialized;
+};
+
+#endif // !_SOFTHSM_V2_P11OBJECTS_H
diff --git a/SoftHSMv2/src/lib/SoftHSM.cpp b/SoftHSMv2/src/lib/SoftHSM.cpp
new file mode 100644 (file)
index 0000000..b06efc2
--- /dev/null
@@ -0,0 +1,11178 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SoftHSM.cpp
+
+ The implementation of the SoftHSM's main class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "access.h"
+#include "Configuration.h"
+#include "SimpleConfigLoader.h"
+#include "MutexFactory.h"
+#include "SecureMemoryRegistry.h"
+#include "CryptoFactory.h"
+#include "AsymmetricAlgorithm.h"
+#include "SymmetricAlgorithm.h"
+#include "AESKey.h"
+#include "DESKey.h"
+#include "RNG.h"
+#include "RSAParameters.h"
+#include "RSAPublicKey.h"
+#include "RSAPrivateKey.h"
+#include "DSAParameters.h"
+#include "DSAPublicKey.h"
+#include "DSAPrivateKey.h"
+#include "ECPublicKey.h"
+#include "ECPrivateKey.h"
+#include "ECParameters.h"
+#include "DHParameters.h"
+#include "DHPublicKey.h"
+#include "DHPrivateKey.h"
+#include "GOSTPublicKey.h"
+#include "GOSTPrivateKey.h"
+#include "cryptoki.h"
+#include "SoftHSM.h"
+#include "osmutex.h"
+#include "SessionManager.h"
+#include "SessionObjectStore.h"
+#include "HandleManager.h"
+#include "P11Objects.h"
+#include "odd.h"
+
+#if defined(WITH_OPENSSL)
+#include "OSSLCryptoFactory.h"
+#else
+#include "BotanCryptoFactory.h"
+#endif
+
+#include <stdlib.h>
+
+// 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
+std::unique_ptr<SoftHSM> SoftHSM::instance(nullptr);
+
+#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
+std::auto_ptr<SoftHSM> SoftHSM::instance(NULL);
+
+#endif
+
+static CK_RV newP11Object(CK_OBJECT_CLASS objClass, CK_KEY_TYPE keyType, CK_CERTIFICATE_TYPE certType, P11Object **p11object)
+{
+       switch(objClass) {
+               case CKO_DATA:
+                       *p11object = new P11DataObj();
+                       break;
+               case CKO_CERTIFICATE:
+                       if (certType == CKC_X_509)
+                               *p11object = new P11X509CertificateObj();
+                       else if (certType == CKC_OPENPGP)
+                               *p11object = new P11OpenPGPPublicKeyObj();
+                       else
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       break;
+               case CKO_PUBLIC_KEY:
+                       if (keyType == CKK_RSA)
+                               *p11object = new P11RSAPublicKeyObj();
+                       else if (keyType == CKK_DSA)
+                               *p11object = new P11DSAPublicKeyObj();
+                       else if (keyType == CKK_EC)
+                               *p11object = new P11ECPublicKeyObj();
+                       else if (keyType == CKK_DH)
+                               *p11object = new P11DHPublicKeyObj();
+                       else if (keyType == CKK_GOSTR3410)
+                               *p11object = new P11GOSTPublicKeyObj();
+                       else
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       break;
+               case CKO_PRIVATE_KEY:
+                       // we need to know the type too
+                       if (keyType == CKK_RSA)
+                               *p11object = new P11RSAPrivateKeyObj();
+                       else if (keyType == CKK_DSA)
+                               *p11object = new P11DSAPrivateKeyObj();
+                       else if (keyType == CKK_EC)
+                               *p11object = new P11ECPrivateKeyObj();
+                       else if (keyType == CKK_DH)
+                               *p11object = new P11DHPrivateKeyObj();
+                       else if (keyType == CKK_GOSTR3410)
+                               *p11object = new P11GOSTPrivateKeyObj();
+                       else
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       break;
+               case CKO_SECRET_KEY:
+                       if ((keyType == CKK_GENERIC_SECRET) ||
+                           (keyType == CKK_MD5_HMAC) ||
+                           (keyType == CKK_SHA_1_HMAC) ||
+                           (keyType == CKK_SHA224_HMAC) ||
+                           (keyType == CKK_SHA256_HMAC) ||
+                           (keyType == CKK_SHA384_HMAC) ||
+                           (keyType == CKK_SHA512_HMAC))
+                       {
+                               P11GenericSecretKeyObj* key = new P11GenericSecretKeyObj();
+                               *p11object = key;
+                               key->setKeyType(keyType);
+                       }
+                       else if (keyType == CKK_AES)
+                       {
+                               *p11object = new P11AESSecretKeyObj();
+                       }
+                       else if ((keyType == CKK_DES) ||
+                                (keyType == CKK_DES2) ||
+                                (keyType == CKK_DES3))
+                       {
+                               P11DESSecretKeyObj* key = new P11DESSecretKeyObj();
+                               *p11object = key;
+                               key->setKeyType(keyType);
+                       }
+                       else if (keyType == CKK_GOST28147)
+                       {
+                               *p11object = new P11GOSTSecretKeyObj();
+                       }
+                       else
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       break;
+               case CKO_DOMAIN_PARAMETERS:
+                       if (keyType == CKK_DSA)
+                               *p11object = new P11DSADomainObj();
+                       else if (keyType == CKK_DH)
+                               *p11object = new P11DHDomainObj();
+                       else
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       break;
+               default:
+                       return CKR_ATTRIBUTE_VALUE_INVALID; // invalid value for a valid argument
+       }
+       return CKR_OK;
+}
+
+static CK_RV extractObjectInformation(CK_ATTRIBUTE_PTR pTemplate,
+                                     CK_ULONG ulCount,
+                                     CK_OBJECT_CLASS &objClass,
+                                     CK_KEY_TYPE &keyType,
+                                     CK_CERTIFICATE_TYPE &certType,
+                                     CK_BBOOL &isOnToken,
+                                     CK_BBOOL &isPrivate,
+                                     bool bImplicit)
+{
+       bool bHasClass = false;
+       bool bHasKeyType = false;
+       bool bHasCertType = false;
+       bool bHasPrivate = false;
+
+       // Extract object information
+       for (CK_ULONG i = 0; i < ulCount; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                               if (pTemplate[i].ulValueLen == sizeof(CK_OBJECT_CLASS))
+                               {
+                                       objClass = *(CK_OBJECT_CLASS_PTR)pTemplate[i].pValue;
+                                       bHasClass = true;
+                               }
+                               break;
+                       case CKA_KEY_TYPE:
+                               if (pTemplate[i].ulValueLen == sizeof(CK_KEY_TYPE))
+                               {
+                                       keyType = *(CK_KEY_TYPE*)pTemplate[i].pValue;
+                                       bHasKeyType = true;
+                               }
+                               break;
+                       case CKA_CERTIFICATE_TYPE:
+                               if (pTemplate[i].ulValueLen == sizeof(CK_CERTIFICATE_TYPE))
+                               {
+                                       certType = *(CK_CERTIFICATE_TYPE*)pTemplate[i].pValue;
+                                       bHasCertType = true;
+                               }
+                               break;
+                       case CKA_TOKEN:
+                               if (pTemplate[i].ulValueLen == sizeof(CK_BBOOL))
+                               {
+                                       isOnToken = *(CK_BBOOL*)pTemplate[i].pValue;
+                               }
+                               break;
+                       case CKA_PRIVATE:
+                               if (pTemplate[i].ulValueLen == sizeof(CK_BBOOL))
+                               {
+                                       isPrivate = *(CK_BBOOL*)pTemplate[i].pValue;
+                                       bHasPrivate = true;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       if (bImplicit)
+       {
+               return CKR_OK;
+       }
+
+       if (!bHasClass)
+       {
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       bool bKeyTypeRequired = (objClass == CKO_PUBLIC_KEY || objClass == CKO_PRIVATE_KEY || objClass == CKO_SECRET_KEY);
+       if (bKeyTypeRequired && !bHasKeyType)
+       {
+                return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       if (objClass == CKO_CERTIFICATE)
+       {
+               if (!bHasCertType)
+               {
+                       return CKR_TEMPLATE_INCOMPLETE;
+               }
+               if (!bHasPrivate)
+               {
+                       // Change default value for certificates
+                       isPrivate = CK_FALSE;
+               }
+       }
+
+       if (objClass == CKO_PUBLIC_KEY && !bHasPrivate)
+       {
+               // Change default value for public keys
+               isPrivate = CK_FALSE;
+       }
+
+       return CKR_OK;
+}
+
+static CK_RV newP11Object(OSObject *object, P11Object **p11object)
+{
+       CK_OBJECT_CLASS objClass = object->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED);
+       CK_KEY_TYPE keyType = CKK_RSA;
+       CK_CERTIFICATE_TYPE certType = CKC_X_509;
+       if (object->attributeExists(CKA_KEY_TYPE))
+               keyType = object->getUnsignedLongValue(CKA_KEY_TYPE, CKK_RSA);
+       if (object->attributeExists(CKA_CERTIFICATE_TYPE))
+               certType = object->getUnsignedLongValue(CKA_CERTIFICATE_TYPE, CKC_X_509);
+       CK_RV rv = newP11Object(objClass,keyType,certType,p11object);
+       if (rv != CKR_OK)
+               return rv;
+       if (!(*p11object)->init(object))
+               return CKR_GENERAL_ERROR; // something went wrong that shouldn't have.
+       return CKR_OK;
+}
+
+#ifdef notyet
+static CK_ATTRIBUTE bsAttribute(CK_ATTRIBUTE_TYPE type, const ByteString &value)
+{
+       CK_ATTRIBUTE attr = {type, (CK_VOID_PTR)value.const_byte_str(), value.size() };
+       return attr;
+}
+#endif
+
+/*****************************************************************************
+ Implementation of SoftHSM class specific functions
+ *****************************************************************************/
+
+// Return the one-and-only instance
+SoftHSM* SoftHSM::i()
+{
+       if (!instance.get())
+       {
+               instance.reset(new SoftHSM());
+       }
+
+       return instance.get();
+}
+
+void SoftHSM::reset()
+{
+       if (instance.get())
+               instance.reset();
+}
+
+// Constructor
+SoftHSM::SoftHSM()
+{
+       isInitialised = false;
+       isRemovable = false;
+       sessionObjectStore = NULL;
+       objectStore = NULL;
+       slotManager = NULL;
+       sessionManager = NULL;
+       handleManager = NULL;
+}
+
+// Destructor
+SoftHSM::~SoftHSM()
+{
+       if (handleManager != NULL) delete handleManager;
+       if (sessionManager != NULL) delete sessionManager;
+       if (slotManager != NULL) delete slotManager;
+       if (objectStore != NULL) delete objectStore;
+       if (sessionObjectStore != NULL) delete sessionObjectStore;
+}
+
+/*****************************************************************************
+ Implementation of PKCS #11 functions
+ *****************************************************************************/
+
+// PKCS #11 initialisation function
+CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs)
+{
+       CK_C_INITIALIZE_ARGS_PTR args;
+
+       // Check if PKCS#11 is already initialized
+       if (isInitialised)
+       {
+               ERROR_MSG("SoftHSM is already initialized");
+               return CKR_CRYPTOKI_ALREADY_INITIALIZED;
+       }
+
+       // Do we have any arguments?
+       if (pInitArgs != NULL_PTR)
+       {
+               args = (CK_C_INITIALIZE_ARGS_PTR)pInitArgs;
+
+               // Must be set to NULL_PTR in this version of PKCS#11
+               if (args->pReserved != NULL_PTR)
+               {
+                       ERROR_MSG("pReserved must be set to NULL_PTR");
+                       return CKR_ARGUMENTS_BAD;
+               }
+
+               // Can we spawn our own threads?
+               // if (args->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS)
+               // {
+               //      DEBUG_MSG("Cannot create threads if CKF_LIBRARY_CANT_CREATE_OS_THREADS is set");
+               //      return CKR_NEED_TO_CREATE_THREADS;
+               // }
+
+               // Are we not supplied with mutex functions?
+               if
+               (
+                       args->CreateMutex == NULL_PTR &&
+                       args->DestroyMutex == NULL_PTR &&
+                       args->LockMutex == NULL_PTR &&
+                       args->UnlockMutex == NULL_PTR
+               )
+               {
+                       // Can we use our own mutex functions?
+                       if (args->flags & CKF_OS_LOCKING_OK)
+                       {
+                               // Use our own mutex functions.
+                               MutexFactory::i()->setCreateMutex(OSCreateMutex);
+                               MutexFactory::i()->setDestroyMutex(OSDestroyMutex);
+                               MutexFactory::i()->setLockMutex(OSLockMutex);
+                               MutexFactory::i()->setUnlockMutex(OSUnlockMutex);
+                               MutexFactory::i()->enable();
+                       }
+                       else
+                       {
+                               // The external application is not using threading
+                               MutexFactory::i()->disable();
+                       }
+               }
+               else
+               {
+                       // We must have all mutex functions
+                       if
+                       (
+                               args->CreateMutex == NULL_PTR ||
+                               args->DestroyMutex == NULL_PTR ||
+                               args->LockMutex == NULL_PTR ||
+                               args->UnlockMutex == NULL_PTR
+                       )
+                       {
+                               ERROR_MSG("Not all mutex functions are supplied");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+
+                       // We could use our own mutex functions if the flag is set,
+                       // but we use the external functions in both cases.
+
+                       // Load the external mutex functions
+                       MutexFactory::i()->setCreateMutex(args->CreateMutex);
+                       MutexFactory::i()->setDestroyMutex(args->DestroyMutex);
+                       MutexFactory::i()->setLockMutex(args->LockMutex);
+                       MutexFactory::i()->setUnlockMutex(args->UnlockMutex);
+                       MutexFactory::i()->enable();
+               }
+       }
+       else
+       {
+               // No concurrent access by multiple threads
+               MutexFactory::i()->disable();
+       }
+
+       // Initiate SecureMemoryRegistry
+       if (SecureMemoryRegistry::i() == NULL)
+       {
+               ERROR_MSG("Could not load the SecureMemoryRegistry");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Build the CryptoFactory
+       if (CryptoFactory::i() == NULL)
+       {
+               ERROR_MSG("Could not load the CryptoFactory");
+               return CKR_GENERAL_ERROR;
+       }
+
+#ifdef WITH_FIPS
+       // Check the FIPS status
+       if (!CryptoFactory::i()->getFipsSelfTestStatus())
+       {
+               ERROR_MSG("The FIPS self test failed");
+               return CKR_FIPS_SELF_TEST_FAILED;
+       }
+#endif
+
+       // (Re)load the configuration
+       if (!Configuration::i()->reload(SimpleConfigLoader::i()))
+       {
+               ERROR_MSG("Could not load the configuration");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Configure the log level
+       if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL)))
+       {
+               ERROR_MSG("Could not set the log level");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Configure object store storage backend used by all tokens.
+       if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND)))
+       {
+               ERROR_MSG("Could not set the storage backend");
+               return CKR_GENERAL_ERROR;
+       }
+
+       sessionObjectStore = new SessionObjectStore();
+
+       // Load the object store
+       objectStore = new ObjectStore(Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR));
+       if (!objectStore->isValid())
+       {
+               WARNING_MSG("Could not load the object store");
+               delete objectStore;
+               objectStore = NULL;
+               delete sessionObjectStore;
+               sessionObjectStore = NULL;
+               return CKR_GENERAL_ERROR;
+       }
+
+       isRemovable = Configuration::i()->getBool("slots.removable", false);
+
+       // Load the slot manager
+       slotManager = new SlotManager(objectStore);
+
+       // Load the session manager
+       sessionManager = new SessionManager();
+
+       // Load the handle manager
+       handleManager = new HandleManager();
+
+       // Set the state to initialised
+       isInitialised = true;
+
+       return CKR_OK;
+}
+
+// PKCS #11 finalisation function
+CK_RV SoftHSM::C_Finalize(CK_VOID_PTR pReserved)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Must be set to NULL_PTR in this version of PKCS#11
+       if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       if (handleManager != NULL) delete handleManager;
+       handleManager = NULL;
+       if (sessionManager != NULL) delete sessionManager;
+       sessionManager = NULL;
+       if (slotManager != NULL) delete slotManager;
+       slotManager = NULL;
+       if (objectStore != NULL) delete objectStore;
+       objectStore = NULL;
+       if (sessionObjectStore != NULL) delete sessionObjectStore;
+       sessionObjectStore = NULL;
+       CryptoFactory::reset();
+       SecureMemoryRegistry::reset();
+
+       isInitialised = false;
+
+       SoftHSM::reset();
+       return CKR_OK;
+}
+
+// Return information about the PKCS #11 module
+CK_RV SoftHSM::C_GetInfo(CK_INFO_PTR pInfo)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+       if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
+       pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
+       memset(pInfo->manufacturerID, ' ', 32);
+       memcpy(pInfo->manufacturerID, "SoftHSM", 7);
+       pInfo->flags = 0;
+       memset(pInfo->libraryDescription, ' ', 32);
+#ifdef WITH_FIPS
+       memcpy(pInfo->libraryDescription, "Implementation of PKCS11+FIPS", 29);
+#else
+       memcpy(pInfo->libraryDescription, "Implementation of PKCS11", 24);
+#endif
+       pInfo->libraryVersion.major = VERSION_MAJOR;
+       pInfo->libraryVersion.minor = VERSION_MINOR;
+
+       return CKR_OK;
+}
+
+// Return a list of available slots
+CK_RV SoftHSM::C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       return slotManager->getSlotList(objectStore, tokenPresent, pSlotList, pulCount);
+}
+
+// Return information about a slot
+CK_RV SoftHSM::C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
+{
+       CK_RV rv;
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL)
+       {
+               return CKR_SLOT_ID_INVALID;
+       }
+
+       rv = slot->getSlotInfo(pInfo);
+       if (rv != CKR_OK) {
+               return rv;
+       }
+
+       if (isRemovable) {
+               pInfo->flags |= CKF_REMOVABLE_DEVICE;
+       }
+
+       return CKR_OK;
+}
+
+// Return information about a token in a slot
+CK_RV SoftHSM::C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL)
+       {
+               return CKR_SLOT_ID_INVALID;
+       }
+
+       Token* token = slot->getToken();
+       if (token == NULL)
+       {
+               return CKR_TOKEN_NOT_PRESENT;
+       }
+
+       return token->getTokenInfo(pInfo);
+}
+
+// Return the list of supported mechanisms for a given slot
+CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
+{
+       // A list with the supported mechanisms
+       CK_ULONG nrSupportedMechanisms = 61;
+#ifdef WITH_ECC
+       nrSupportedMechanisms += 3;
+#endif
+#ifdef WITH_FIPS
+       nrSupportedMechanisms -= 9;
+#endif
+#ifdef WITH_GOST
+       nrSupportedMechanisms += 5;
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       nrSupportedMechanisms += 1;
+#endif
+#ifdef WITH_RAW_PSS
+       nrSupportedMechanisms += 1; // CKM_RSA_PKCS_PSS
+#endif
+#ifdef WITH_AES_GCM
+       nrSupportedMechanisms += 1;
+#endif
+
+       CK_MECHANISM_TYPE supportedMechanisms[] =
+       {
+#ifndef WITH_FIPS
+               CKM_MD5,
+#endif
+               CKM_SHA_1,
+               CKM_SHA224,
+               CKM_SHA256,
+               CKM_SHA384,
+               CKM_SHA512,
+#ifndef WITH_FIPS
+               CKM_MD5_HMAC,
+#endif
+               CKM_SHA_1_HMAC,
+               CKM_SHA224_HMAC,
+               CKM_SHA256_HMAC,
+               CKM_SHA384_HMAC,
+               CKM_SHA512_HMAC,
+               CKM_RSA_PKCS_KEY_PAIR_GEN,
+               CKM_RSA_PKCS,
+               CKM_RSA_X_509,
+#ifndef WITH_FIPS
+               CKM_MD5_RSA_PKCS,
+#endif
+               CKM_SHA1_RSA_PKCS,
+               CKM_RSA_PKCS_OAEP,
+               CKM_SHA224_RSA_PKCS,
+               CKM_SHA256_RSA_PKCS,
+               CKM_SHA384_RSA_PKCS,
+               CKM_SHA512_RSA_PKCS,
+#ifdef WITH_RAW_PSS
+               CKM_RSA_PKCS_PSS,
+#endif
+               CKM_SHA1_RSA_PKCS_PSS,
+               CKM_SHA224_RSA_PKCS_PSS,
+               CKM_SHA256_RSA_PKCS_PSS,
+               CKM_SHA384_RSA_PKCS_PSS,
+               CKM_SHA512_RSA_PKCS_PSS,
+#ifndef WITH_FIPS
+               CKM_DES_KEY_GEN,
+#endif
+               CKM_DES2_KEY_GEN,
+               CKM_DES3_KEY_GEN,
+#ifndef WITH_FIPS
+               CKM_DES_ECB,
+               CKM_DES_CBC,
+               CKM_DES_CBC_PAD,
+               CKM_DES_ECB_ENCRYPT_DATA,
+               CKM_DES_CBC_ENCRYPT_DATA,
+#endif
+               CKM_DES3_ECB,
+               CKM_DES3_CBC,
+               CKM_DES3_CBC_PAD,
+               CKM_DES3_ECB_ENCRYPT_DATA,
+               CKM_DES3_CBC_ENCRYPT_DATA,
+               CKM_DES3_CMAC,
+               CKM_AES_KEY_GEN,
+               CKM_AES_ECB,
+               CKM_AES_CBC,
+               CKM_AES_CBC_PAD,
+               CKM_AES_CTR,
+#ifdef WITH_AES_GCM
+               CKM_AES_GCM,
+#endif
+               CKM_AES_KEY_WRAP,
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               CKM_AES_KEY_WRAP_PAD,
+#endif
+               CKM_AES_ECB_ENCRYPT_DATA,
+               CKM_AES_CBC_ENCRYPT_DATA,
+               CKM_AES_CMAC,
+               CKM_DSA_PARAMETER_GEN,
+               CKM_DSA_KEY_PAIR_GEN,
+               CKM_DSA,
+               CKM_DSA_SHA1,
+               CKM_DSA_SHA224,
+               CKM_DSA_SHA256,
+               CKM_DSA_SHA384,
+               CKM_DSA_SHA512,
+               CKM_DH_PKCS_KEY_PAIR_GEN,
+               CKM_DH_PKCS_PARAMETER_GEN,
+               CKM_DH_PKCS_DERIVE,
+#ifdef WITH_ECC
+               CKM_EC_KEY_PAIR_GEN,
+               CKM_ECDSA,
+               CKM_ECDH1_DERIVE,
+#endif
+#ifdef WITH_GOST
+               CKM_GOSTR3411,
+               CKM_GOSTR3411_HMAC,
+               CKM_GOSTR3410_KEY_PAIR_GEN,
+               CKM_GOSTR3410,
+               CKM_GOSTR3410_WITH_GOSTR3411
+#endif
+       };
+
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+       if (pulCount == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL)
+       {
+               return CKR_SLOT_ID_INVALID;
+       }
+
+       if (pMechanismList == NULL_PTR)
+       {
+               *pulCount = nrSupportedMechanisms;
+
+               return CKR_OK;
+       }
+
+       if (*pulCount < nrSupportedMechanisms)
+       {
+               *pulCount = nrSupportedMechanisms;
+
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       *pulCount = nrSupportedMechanisms;
+
+       for (CK_ULONG i = 0; i < nrSupportedMechanisms; i ++)
+       {
+               pMechanismList[i] = supportedMechanisms[i];
+       }
+
+       return CKR_OK;
+}
+
+// Return more information about a mechanism for a given slot
+CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo)
+{
+       unsigned long rsaMinSize, rsaMaxSize;
+       unsigned long dsaMinSize, dsaMaxSize;
+       unsigned long dhMinSize, dhMaxSize;
+#ifdef WITH_ECC
+       unsigned long ecdsaMinSize, ecdsaMaxSize;
+       unsigned long ecdhMinSize, ecdhMaxSize;
+#endif
+
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+       if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL)
+       {
+               return CKR_SLOT_ID_INVALID;
+       }
+
+       AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+       if (rsa != NULL)
+       {
+               rsaMinSize = rsa->getMinKeySize();
+               rsaMaxSize = rsa->getMaxKeySize();
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+
+       AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+       if (dsa != NULL)
+       {
+               dsaMinSize = dsa->getMinKeySize();
+               // Limitation in PKCS#11
+               if (dsaMinSize < 512)
+               {
+                       dsaMinSize = 512;
+               }
+
+               dsaMaxSize = dsa->getMaxKeySize();
+               // Limitation in PKCS#11
+               if (dsaMaxSize > 1024)
+               {
+                       dsaMaxSize = 1024;
+               }
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh != NULL)
+       {
+               dhMinSize = dh->getMinKeySize();
+               dhMaxSize = dh->getMaxKeySize();
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+#ifdef WITH_ECC
+       AsymmetricAlgorithm* ecdsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+       if (ecdsa != NULL)
+       {
+               ecdsaMinSize = ecdsa->getMinKeySize();
+               ecdsaMaxSize = ecdsa->getMaxKeySize();
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdsa);
+
+       AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH);
+       if (ecdh != NULL)
+       {
+               ecdhMinSize = ecdh->getMinKeySize();
+               ecdhMaxSize = ecdh->getMaxKeySize();
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+#endif
+
+       switch (type)
+       {
+#ifndef WITH_FIPS
+               case CKM_MD5:
+#endif
+               case CKM_SHA_1:
+               case CKM_SHA224:
+               case CKM_SHA256:
+               case CKM_SHA384:
+               case CKM_SHA512:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_DIGEST;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_MD5_HMAC:
+                       pInfo->ulMinKeySize = 16;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+#endif
+               case CKM_SHA_1_HMAC:
+                       pInfo->ulMinKeySize = 20;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_SHA224_HMAC:
+                       pInfo->ulMinKeySize = 28;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_SHA256_HMAC:
+                       pInfo->ulMinKeySize = 32;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_SHA384_HMAC:
+                       pInfo->ulMinKeySize = 48;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_SHA512_HMAC:
+                       pInfo->ulMinKeySize = 64;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_RSA_PKCS_KEY_PAIR_GEN:
+                       pInfo->ulMinKeySize = rsaMinSize;
+                       pInfo->ulMaxKeySize = rsaMaxSize;
+                       pInfo->flags = CKF_GENERATE_KEY_PAIR;
+                       break;
+               case CKM_RSA_PKCS:
+                       pInfo->ulMinKeySize = rsaMinSize;
+                       pInfo->ulMaxKeySize = rsaMaxSize;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
+                       break;
+               case CKM_RSA_X_509:
+                       pInfo->ulMinKeySize = rsaMinSize;
+                       pInfo->ulMaxKeySize = rsaMaxSize;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_ENCRYPT | CKF_DECRYPT;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_MD5_RSA_PKCS:
+#endif
+               case CKM_SHA1_RSA_PKCS:
+               case CKM_SHA224_RSA_PKCS:
+               case CKM_SHA256_RSA_PKCS:
+               case CKM_SHA384_RSA_PKCS:
+               case CKM_SHA512_RSA_PKCS:
+#ifdef WITH_RAW_PSS
+               case CKM_RSA_PKCS_PSS:
+#endif
+               case CKM_SHA1_RSA_PKCS_PSS:
+               case CKM_SHA224_RSA_PKCS_PSS:
+               case CKM_SHA256_RSA_PKCS_PSS:
+               case CKM_SHA384_RSA_PKCS_PSS:
+               case CKM_SHA512_RSA_PKCS_PSS:
+                       pInfo->ulMinKeySize = rsaMinSize;
+                       pInfo->ulMaxKeySize = rsaMaxSize;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_RSA_PKCS_OAEP:
+                       pInfo->ulMinKeySize = rsaMinSize;
+                       pInfo->ulMaxKeySize = rsaMaxSize;
+                       pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_DES_KEY_GEN:
+#endif
+               case CKM_DES2_KEY_GEN:
+               case CKM_DES3_KEY_GEN:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_GENERATE;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_DES_ECB:
+               case CKM_DES_CBC:
+               case CKM_DES_CBC_PAD:
+#endif
+               case CKM_DES3_ECB:
+               case CKM_DES3_CBC:
+               case CKM_DES3_CBC_PAD:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT;
+                       break;
+               case CKM_DES3_CMAC:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_AES_KEY_GEN:
+                       pInfo->ulMinKeySize = 16;
+                       pInfo->ulMaxKeySize = 32;
+                       pInfo->flags = CKF_GENERATE;
+                       break;
+               case CKM_AES_ECB:
+               case CKM_AES_CBC:
+               case CKM_AES_CBC_PAD:
+               case CKM_AES_CTR:
+#ifdef WITH_AES_GCM
+               case CKM_AES_GCM:
+#endif
+                       pInfo->ulMinKeySize = 16;
+                       pInfo->ulMaxKeySize = 32;
+                       pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT;
+                       break;
+               case CKM_AES_KEY_WRAP:
+                       pInfo->ulMinKeySize = 16;
+                       pInfo->ulMaxKeySize = 0x80000000;
+                       pInfo->flags = CKF_WRAP | CKF_UNWRAP;
+                       break;
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               case CKM_AES_KEY_WRAP_PAD:
+                       pInfo->ulMinKeySize = 1;
+                       pInfo->ulMaxKeySize = 0x80000000;
+                       pInfo->flags = CKF_WRAP | CKF_UNWRAP;
+                       break;
+#endif
+#ifndef WITH_FIPS
+               case CKM_DES_ECB_ENCRYPT_DATA:
+               case CKM_DES_CBC_ENCRYPT_DATA:
+#endif
+               case CKM_DES3_ECB_ENCRYPT_DATA:
+               case CKM_DES3_CBC_ENCRYPT_DATA:
+               case CKM_AES_ECB_ENCRYPT_DATA:
+               case CKM_AES_CBC_ENCRYPT_DATA:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_DERIVE;
+                       break;
+               case CKM_AES_CMAC:
+                       pInfo->ulMinKeySize = 16;
+                       pInfo->ulMaxKeySize = 32;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_DSA_PARAMETER_GEN:
+                       pInfo->ulMinKeySize = dsaMinSize;
+                       pInfo->ulMaxKeySize = dsaMaxSize;
+                       pInfo->flags = CKF_GENERATE;
+                       break;
+               case CKM_DSA_KEY_PAIR_GEN:
+                       pInfo->ulMinKeySize = dsaMinSize;
+                       pInfo->ulMaxKeySize = dsaMaxSize;
+                       pInfo->flags = CKF_GENERATE_KEY_PAIR;
+                       break;
+               case CKM_DSA:
+               case CKM_DSA_SHA1:
+               case CKM_DSA_SHA224:
+               case CKM_DSA_SHA256:
+               case CKM_DSA_SHA384:
+               case CKM_DSA_SHA512:
+                       pInfo->ulMinKeySize = dsaMinSize;
+                       pInfo->ulMaxKeySize = dsaMaxSize;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_DH_PKCS_KEY_PAIR_GEN:
+                       pInfo->ulMinKeySize = dhMinSize;
+                       pInfo->ulMaxKeySize = dhMaxSize;
+                       pInfo->flags = CKF_GENERATE_KEY_PAIR;
+                       break;
+               case CKM_DH_PKCS_PARAMETER_GEN:
+                       pInfo->ulMinKeySize = dhMinSize;
+                       pInfo->ulMaxKeySize = dhMaxSize;
+                       pInfo->flags = CKF_GENERATE;
+                       break;
+               case CKM_DH_PKCS_DERIVE:
+                       pInfo->ulMinKeySize = dhMinSize;
+                       pInfo->ulMaxKeySize = dhMaxSize;
+                       pInfo->flags = CKF_DERIVE;
+                       break;
+#ifdef WITH_ECC
+               case CKM_EC_KEY_PAIR_GEN:
+                       pInfo->ulMinKeySize = ecdsaMinSize;
+                       pInfo->ulMaxKeySize = ecdsaMaxSize;
+#define CKF_EC_COMMOM  (CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS)
+                       pInfo->flags = CKF_GENERATE_KEY_PAIR | CKF_EC_COMMOM;
+                       break;
+               case CKM_ECDSA:
+                       pInfo->ulMinKeySize = ecdsaMinSize;
+                       pInfo->ulMaxKeySize = ecdsaMaxSize;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_EC_COMMOM;
+                       break;
+               case CKM_ECDH1_DERIVE:
+                       pInfo->ulMinKeySize = ecdhMinSize;
+                       pInfo->ulMaxKeySize = ecdhMaxSize;
+                       pInfo->flags = CKF_DERIVE;
+                       break;
+#endif
+#ifdef WITH_GOST
+               case CKM_GOSTR3411:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_DIGEST;
+                       break;
+               case CKM_GOSTR3411_HMAC:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 32;
+                       pInfo->ulMaxKeySize = 512;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_GOSTR3410_KEY_PAIR_GEN:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_GENERATE_KEY_PAIR;
+                       break;
+               case CKM_GOSTR3410:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+               case CKM_GOSTR3410_WITH_GOSTR3411:
+                       // Key size is not in use
+                       pInfo->ulMinKeySize = 0;
+                       pInfo->ulMaxKeySize = 0;
+                       pInfo->flags = CKF_SIGN | CKF_VERIFY;
+                       break;
+#endif
+               default:
+                       DEBUG_MSG("The selected mechanism is not supported");
+                       return CKR_MECHANISM_INVALID;
+                       break;
+       }
+
+       return CKR_OK;
+}
+
+// Initialise the token in the specified slot
+CK_RV SoftHSM::C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL)
+       {
+               return CKR_SLOT_ID_INVALID;
+       }
+
+       // Check if any session is open with this token.
+       if (sessionManager->haveSession(slotID))
+       {
+               return CKR_SESSION_EXISTS;
+       }
+
+       // Check the PIN
+       if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (ulPinLen < MIN_PIN_LEN || ulPinLen > MAX_PIN_LEN) return CKR_PIN_INCORRECT;
+
+       ByteString soPIN(pPin, ulPinLen);
+
+       return slot->initToken(soPIN, pLabel);
+}
+
+// Initialise the user PIN
+CK_RV SoftHSM::C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // The SO must be logged in
+       if (session->getState() != CKS_RW_SO_FUNCTIONS) return CKR_USER_NOT_LOGGED_IN;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the PIN
+       if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (ulPinLen < MIN_PIN_LEN || ulPinLen > MAX_PIN_LEN) return CKR_PIN_LEN_RANGE;
+
+       ByteString userPIN(pPin, ulPinLen);
+
+       return token->initUserPIN(userPIN);
+}
+
+// Change the PIN
+CK_RV SoftHSM::C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen)
+{
+       CK_RV rv = CKR_OK;
+
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check the new PINs
+       if (pOldPin == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pNewPin == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (ulNewLen < MIN_PIN_LEN || ulNewLen > MAX_PIN_LEN) return CKR_PIN_LEN_RANGE;
+
+       ByteString oldPIN(pOldPin, ulOldLen);
+       ByteString newPIN(pNewPin, ulNewLen);
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       switch (session->getState())
+       {
+               case CKS_RW_PUBLIC_SESSION:
+               case CKS_RW_USER_FUNCTIONS:
+                       rv = token->setUserPIN(oldPIN, newPIN);
+                       break;
+               case CKS_RW_SO_FUNCTIONS:
+                       rv = token->setSOPIN(oldPIN, newPIN);
+                       break;
+               default:
+                       return CKR_SESSION_READ_ONLY;
+       }
+
+       return rv;
+}
+
+// Open a new session to the specified slot
+CK_RV SoftHSM::C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       Slot* slot = slotManager->getSlot(slotID);
+
+       CK_RV rv = sessionManager->openSession(slot, flags, pApplication, notify, phSession);
+       if (rv != CKR_OK)
+               return rv;
+
+       // Get a pointer to the session object and store it in the handle manager.
+       Session* session = sessionManager->getSession(*phSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+       *phSession = handleManager->addSession(slotID,session);
+
+       return CKR_OK;
+}
+
+// Close the given session
+CK_RV SoftHSM::C_CloseSession(CK_SESSION_HANDLE hSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Tell the handle manager the session has been closed.
+       handleManager->sessionClosed(hSession);
+
+
+       // Tell the session object store that the session has closed.
+       sessionObjectStore->sessionClosed(hSession);
+
+       // Tell the session manager the session has been closed.
+       return sessionManager->closeSession(session->getHandle());
+}
+
+// Close all open sessions
+CK_RV SoftHSM::C_CloseAllSessions(CK_SLOT_ID slotID)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the slot
+       Slot* slot = slotManager->getSlot(slotID);
+       if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+       // Get the token
+       Token* token = slot->getToken();
+       if (token == NULL) return CKR_TOKEN_NOT_PRESENT;
+
+       // Tell the handle manager all sessions were closed for the given slotID.
+       // The handle manager should then remove all session and object handles for this slot.
+       handleManager->allSessionsClosed(slotID);
+
+       // Tell the session object store that all sessions were closed for the given slotID.
+       // The session object store should then remove all session objects for this slot.
+       sessionObjectStore->allSessionsClosed(slotID);
+
+       // Finally tell the session manager tho close all sessions for the given slot.
+       // This will also trigger a logout on the associated token to occur.
+       return sessionManager->closeAllSessions(slot);
+}
+
+// Retrieve information about the specified session
+CK_RV SoftHSM::C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return session->getInfo(pInfo);
+}
+
+// Determine the state of a running operation in a session
+CK_RV SoftHSM::C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pOperationState*/, CK_ULONG_PTR /*pulOperationStateLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Set the operation sate in a session
+CK_RV SoftHSM::C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pOperationState*/, CK_ULONG /*ulOperationStateLen*/, CK_OBJECT_HANDLE /*hEncryptionKey*/, CK_OBJECT_HANDLE /*hAuthenticationKey*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Login on the token in the specified session
+CK_RV SoftHSM::C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+       CK_RV rv = CKR_OK;
+
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the PIN
+       if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       ByteString pin(pPin, ulPinLen);
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       switch (userType)
+       {
+               case CKU_SO:
+                       // There cannot exist a R/O session on this slot
+                       if (sessionManager->haveROSession(session->getSlot()->getSlotID())) return CKR_SESSION_READ_ONLY_EXISTS;
+
+                       // Login
+                       rv = token->loginSO(pin);
+                       break;
+               case CKU_USER:
+                       // Login
+                       rv = token->loginUser(pin);
+                       break;
+               case CKU_CONTEXT_SPECIFIC:
+                       // Check if re-authentication is required
+                       if (!session->getReAuthentication()) return CKR_OPERATION_NOT_INITIALIZED;
+
+                       // Re-authenticate
+                       rv = token->reAuthenticate(pin);
+                       if (rv == CKR_OK) session->setReAuthentication(false);
+                       break;
+               default:
+                       return CKR_USER_TYPE_INVALID;
+       }
+
+       return rv;
+}
+
+// Log out of the token in the specified session
+CK_RV SoftHSM::C_Logout(CK_SESSION_HANDLE hSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Logout
+       token->logout();
+
+       // [PKCS#11 v2.40, C_Logout] When logout is successful...
+       // a. Any of the application's handles to private objects become invalid.
+       // b. Even if a user is later logged back into the token those handles remain invalid.
+       // c. All private session objects from sessions belonging to the application are destroyed.
+
+       // Have the handle manager remove all handles pointing to private objects for this slot.
+       CK_SLOT_ID slotID = session->getSlot()->getSlotID();
+       handleManager->tokenLoggedOut(slotID);
+       sessionObjectStore->tokenLoggedOut(slotID);
+
+       return CKR_OK;
+}
+
+// Create a new object on the token in the specified session using the given attribute template
+CK_RV SoftHSM::C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
+{
+       return this->CreateObject(hSession,pTemplate,ulCount,phObject,OBJECT_OP_CREATE);
+}
+
+// Create a copy of the object with the specified handle
+CK_RV SoftHSM::C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phNewObject == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       *phNewObject = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the slot
+       Slot* slot = session->getSlot();
+       if (slot == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Check the object handle.
+       OSObject *object = (OSObject *)handleManager->getObject(hObject);
+       if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL wasOnToken = object->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL wasPrivate = object->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), wasOnToken, wasPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if the object is copyable
+       CK_BBOOL isCopyable = object->getBooleanValue(CKA_COPYABLE, true);
+       if (!isCopyable) return CKR_ACTION_PROHIBITED;
+
+       // Extract critical information from the template
+       CK_BBOOL isOnToken = wasOnToken;
+       CK_BBOOL isPrivate = wasPrivate;
+
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               if ((pTemplate[i].type == CKA_TOKEN) && (pTemplate[i].ulValueLen == sizeof(CK_BBOOL)))
+               {
+                       isOnToken = *(CK_BBOOL*)pTemplate[i].pValue;
+                       continue;
+               }
+               if ((pTemplate[i].type == CKA_PRIVATE) && (pTemplate[i].ulValueLen == sizeof(CK_BBOOL)))
+               {
+                       isPrivate = *(CK_BBOOL*)pTemplate[i].pValue;
+                       continue;
+               }
+       }
+
+       // Check privacy does not downgrade
+       if (wasPrivate && !isPrivate) return CKR_TEMPLATE_INCONSISTENT;
+
+       // Check write user credentials
+       rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Create the object in session or on the token
+       OSObject *newobject = NULL_PTR;
+       if (isOnToken)
+       {
+               newobject = (OSObject*) token->createObject();
+       }
+       else
+       {
+               newobject = sessionObjectStore->createObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE);
+       }
+       if (newobject == NULL) return CKR_GENERAL_ERROR;
+
+       // Copy attributes from object class (CKA_CLASS=0 so the first)
+       if (!newobject->startTransaction())
+       {
+               newobject->destroyObject();
+               return CKR_FUNCTION_FAILED;
+       }
+
+       CK_ATTRIBUTE_TYPE attrType = CKA_CLASS;
+       do
+       {
+               if (!object->attributeExists(attrType))
+               {
+                       rv = CKR_FUNCTION_FAILED;
+                       break;
+               }
+
+               OSAttribute attr = object->getAttribute(attrType);
+
+               // Upgrade privacy has to encrypt byte strings
+               if (!wasPrivate && isPrivate &&
+                   attr.isByteStringAttribute() &&
+                   attr.getByteStringValue().size() != 0)
+               {
+                       ByteString value;
+                       if (!token->encrypt(attr.getByteStringValue(), value) ||
+                           !newobject->setAttribute(attrType, value))
+                       {
+                               rv = CKR_FUNCTION_FAILED;
+                               break;
+                       }
+               }
+               else
+               {
+                       if (!newobject->setAttribute(attrType, attr))
+                       {
+                               rv = CKR_FUNCTION_FAILED;
+                               break;
+                       }
+               }
+               attrType = object->nextAttributeType(attrType);
+       }
+       while (attrType != CKA_CLASS);
+
+       if (rv != CKR_OK)
+       {
+               newobject->abortTransaction();
+       }
+       else if (!newobject->commitTransaction())
+       {
+               rv = CKR_FUNCTION_FAILED;
+       }
+
+       if (rv != CKR_OK)
+       {
+               newobject->destroyObject();
+               return rv;
+       }
+
+       // Get the new P11 object
+       P11Object* newp11object = NULL;
+       rv = newP11Object(newobject,&newp11object);
+       if (rv != CKR_OK)
+       {
+               newobject->destroyObject();
+               return rv;
+       }
+
+       // Apply the template
+       rv = newp11object->saveTemplate(token, isPrivate != CK_FALSE, pTemplate, ulCount, OBJECT_OP_COPY);
+       delete newp11object;
+
+       if (rv != CKR_OK)
+       {
+               newobject->destroyObject();
+               return rv;
+       }
+
+       // Set handle
+       if (isOnToken)
+       {
+               *phNewObject = handleManager->addTokenObject(slot->getSlotID(), isPrivate != CK_FALSE, newobject);
+       }
+       else
+       {
+               *phNewObject = handleManager->addSessionObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE, newobject);
+       }
+
+       return CKR_OK;
+}
+
+// Destroy the specified object
+CK_RV SoftHSM::C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Check the object handle.
+       OSObject *object = (OSObject *)handleManager->getObject(hObject);
+       if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials
+       CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Check if the object is destroyable
+       CK_BBOOL isDestroyable = object->getBooleanValue(CKA_DESTROYABLE, true);
+       if (!isDestroyable) return CKR_ACTION_PROHIBITED;
+
+       // Tell the handleManager to forget about the object.
+       handleManager->destroyObject(hObject);
+
+       // Destroy the object
+       if (!object->destroyObject())
+               return CKR_FUNCTION_FAILED;
+
+       return CKR_OK;
+}
+
+// Determine the size of the specified object
+CK_RV SoftHSM::C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pulSize == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Check the object handle.
+       OSObject *object = (OSObject *)handleManager->getObject(hObject);
+       if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       *pulSize = CK_UNAVAILABLE_INFORMATION;
+
+       return CKR_OK;
+}
+
+// Retrieve the specified attributes for the given object
+CK_RV SoftHSM::C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pTemplate == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the object handle.
+       OSObject *object = (OSObject *)handleManager->getObject(hObject);
+       if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               // CKR_USER_NOT_LOGGED_IN is not a valid return code for this function,
+               // so we use CKR_GENERAL_ERROR.
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Wrap a P11Object around the OSObject so we can access the attributes in the
+       // context of the object in which it is defined.
+       P11Object* p11object = NULL;
+       rv = newP11Object(object,&p11object);
+       if (rv != CKR_OK)
+               return rv;
+
+       // Ask the P11Object to fill the template with attribute values.
+       rv = p11object->loadTemplate(token, pTemplate,ulCount);
+       delete p11object;
+       return rv;
+}
+
+// Change or set the value of the specified attributes on the specified object
+CK_RV SoftHSM::C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pTemplate == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the object handle.
+       OSObject *object = (OSObject *)handleManager->getObject(hObject);
+       if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials
+       CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Check if the object is modifiable
+       CK_BBOOL isModifiable = object->getBooleanValue(CKA_MODIFIABLE, true);
+       if (!isModifiable) return CKR_ACTION_PROHIBITED;
+
+       // Wrap a P11Object around the OSObject so we can access the attributes in the
+       // context of the object in which it is defined.
+       P11Object* p11object = NULL;
+       rv = newP11Object(object,&p11object);
+       if (rv != CKR_OK)
+               return rv;
+
+       // Ask the P11Object to save the template with attribute values.
+       rv = p11object->saveTemplate(token, isPrivate != CK_FALSE, pTemplate,ulCount,OBJECT_OP_SET);
+       delete p11object;
+       return rv;
+}
+
+// Initialise object search in the specified session using the specified attribute template as search parameters
+CK_RV SoftHSM::C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the slot
+       Slot* slot = session->getSlot();
+       if (slot == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Determine whether we have a public session or not.
+       bool isPublicSession;
+       switch (session->getState()) {
+               case CKS_RO_USER_FUNCTIONS:
+               case CKS_RW_USER_FUNCTIONS:
+                       isPublicSession = false;
+                       break;
+               default:
+                       isPublicSession = true;
+       }
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       session->setOpType(SESSION_OP_FIND);
+       FindOperation *findOp = FindOperation::create();
+
+       // Check if we are out of memory
+       if (findOp == NULL_PTR) return CKR_HOST_MEMORY;
+
+       std::set<OSObject*> allObjects;
+       token->getObjects(allObjects);
+       sessionObjectStore->getObjects(slot->getSlotID(),allObjects);
+
+       std::set<CK_OBJECT_HANDLE> handles;
+       std::set<OSObject*>::iterator it;
+       for (it=allObjects.begin(); it != allObjects.end(); ++it)
+       {
+               // Refresh object and check if it is valid
+               if (!(*it)->isValid()) {
+                       DEBUG_MSG("Object is not valid, skipping");
+                       continue;
+               }
+
+               // Determine if the object has CKA_PRIVATE set to CK_TRUE
+               bool isPrivateObject = (*it)->getBooleanValue(CKA_PRIVATE, true);
+
+               // If the object is private, and we are in a public session then skip it !
+               if (isPublicSession && isPrivateObject)
+                       continue; // skip object
+
+               // Perform the actual attribute matching.
+               bool bAttrMatch = true; // We let an empty template match everything.
+               for (CK_ULONG i=0; i<ulCount; ++i)
+               {
+                       bAttrMatch = false;
+
+                       if (!(*it)->attributeExists(pTemplate[i].type))
+                               break;
+
+                       OSAttribute attr = (*it)->getAttribute(pTemplate[i].type);
+
+                       if (attr.isBooleanAttribute())
+                       {
+                               if (sizeof(CK_BBOOL) != pTemplate[i].ulValueLen)
+                                       break;
+                               bool bTemplateValue = (*(CK_BBOOL*)pTemplate[i].pValue == CK_TRUE);
+                               if (attr.getBooleanValue() != bTemplateValue)
+                                       break;
+                       }
+                       else
+                       {
+                               if (attr.isUnsignedLongAttribute())
+                               {
+                                       if (sizeof(CK_ULONG) != pTemplate[i].ulValueLen)
+                                               break;
+                                       CK_ULONG ulTemplateValue = *(CK_ULONG_PTR)pTemplate[i].pValue;
+                                       if (attr.getUnsignedLongValue() != ulTemplateValue)
+                                               break;
+                               }
+                               else
+                               {
+                                       if (attr.isByteStringAttribute())
+                                       {
+                                               ByteString bsAttrValue;
+                                               if (isPrivateObject && attr.getByteStringValue().size() != 0)
+                                               {
+                                                       if (!token->decrypt(attr.getByteStringValue(), bsAttrValue))
+                                                       {
+                                                               delete findOp;
+                                                               return CKR_GENERAL_ERROR;
+                                                       }
+                                               }
+                                               else
+                                                       bsAttrValue = attr.getByteStringValue();
+
+                                               if (bsAttrValue.size() != pTemplate[i].ulValueLen)
+                                                       break;
+                                               if (pTemplate[i].ulValueLen != 0)
+                                               {
+                                                       ByteString bsTemplateValue((const unsigned char*)pTemplate[i].pValue, pTemplate[i].ulValueLen);
+                                                       if (bsAttrValue != bsTemplateValue)
+                                                               break;
+                                               }
+                                       }
+                                       else
+                                               break;
+                               }
+                       }
+                       // The attribute matched !
+                       bAttrMatch = true;
+               }
+
+               if (bAttrMatch)
+               {
+                       CK_SLOT_ID slotID = slot->getSlotID();
+                       bool isOnToken = (*it)->getBooleanValue(CKA_TOKEN, false);
+                       bool isPrivate = (*it)->getBooleanValue(CKA_PRIVATE, true);
+                       // Create an object handle for every returned object.
+                       CK_OBJECT_HANDLE hObject;
+                       if (isOnToken)
+                               hObject = handleManager->addTokenObject(slotID,isPrivate,*it);
+                       else
+                               hObject = handleManager->addSessionObject(slotID,hSession,isPrivate,*it);
+                       if (hObject == CK_INVALID_HANDLE)
+                       {
+                               delete findOp;
+                               return CKR_GENERAL_ERROR;
+                       }
+                       handles.insert(hObject);
+               }
+       }
+
+       // Storing the object handles for the find will protect the library
+       // whenever a stale object handle is used to access the library.
+       findOp->setHandles(handles);
+
+       session->setFindOp(findOp);
+
+       return CKR_OK;
+}
+
+// Continue the search for objects in the specified session
+CK_RV SoftHSM::C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+       if (phObject == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulObjectCount == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_FIND) return CKR_OPERATION_NOT_INITIALIZED;
+
+       // return the object handles that have been added to the find operation.
+       FindOperation *findOp = session->getFindOp();
+       if (findOp == NULL) return CKR_GENERAL_ERROR;
+
+       // Ask the find operation to retrieve the object handles
+       *pulObjectCount = findOp->retrieveHandles(phObject,ulMaxObjectCount);
+
+       // Erase the object handles from the find operation.
+       findOp->eraseHandles(0,*pulObjectCount);
+
+       return CKR_OK;
+}
+
+// Finish searching for objects
+CK_RV SoftHSM::C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_FIND) return CKR_OPERATION_NOT_INITIALIZED;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Encrypt*/Decrypt*() is for Symmetrical ciphers too
+static bool isSymMechanism(CK_MECHANISM_PTR pMechanism)
+{
+       if (pMechanism == NULL_PTR) return false;
+
+       switch(pMechanism->mechanism) {
+               case CKM_DES_ECB:
+               case CKM_DES_CBC:
+               case CKM_DES_CBC_PAD:
+               case CKM_DES3_ECB:
+               case CKM_DES3_CBC:
+               case CKM_DES3_CBC_PAD:
+               case CKM_AES_ECB:
+               case CKM_AES_CBC:
+               case CKM_AES_CBC_PAD:
+               case CKM_AES_CTR:
+               case CKM_AES_GCM:
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+// SymAlgorithm version of C_EncryptInit
+CK_RV SoftHSM::SymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for encryption
+       if (!key->getBooleanValue(CKA_ENCRYPT, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get the symmetric algorithm matching the mechanism
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       SymMode::Type mode = SymMode::Unknown;
+       bool padding = false;
+       ByteString iv;
+       size_t bb = 8;
+       size_t counterBits = 0;
+       ByteString aad;
+       size_t tagBytes = 0;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_DES_ECB:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES_CBC:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_DES_CBC_PAD:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+#endif
+               case CKM_DES3_ECB:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES3_CBC:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_DES3_CBC_PAD:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_AES_ECB:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::ECB;
+                       break;
+               case CKM_AES_CBC:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       break;
+               case CKM_AES_CBC_PAD:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       break;
+               case CKM_AES_CTR:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CTR;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_AES_CTR_PARAMS))
+                       {
+                               DEBUG_MSG("CTR mode requires a counter block");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       counterBits = CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->ulCounterBits;
+                       if (counterBits == 0 || counterBits > 128)
+                       {
+                               DEBUG_MSG("Invalid ulCounterBits");
+                               return CKR_MECHANISM_PARAM_INVALID;
+                       }
+                       iv.resize(16);
+                       memcpy(&iv[0], CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->cb, 16);
+                       break;
+#ifdef WITH_AES_GCM
+               case CKM_AES_GCM:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::GCM;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_GCM_PARAMS))
+                       {
+                               DEBUG_MSG("GCM mode requires parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen);
+                       memcpy(&iv[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pIv, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen);
+                       aad.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
+                       memcpy(&aad[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pAAD, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
+                       tagBytes = CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulTagBits;
+                       if (tagBytes > 128 || tagBytes % 8 != 0)
+                       {
+                               DEBUG_MSG("Invalid ulTagBits value");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       tagBytes = tagBytes / 8;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* secretkey = new SymmetricKey();
+
+       if (getSymmetricKey(secretkey, token, key) != CKR_OK)
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // adjust key bit length
+       secretkey->setBitLen(secretkey->getKeyBits().size() * bb);
+
+       // Initialize encryption
+       if (!cipher->encryptInit(secretkey, mode, iv, padding, counterBits, aad, tagBytes))
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       session->setOpType(SESSION_OP_ENCRYPT);
+       session->setSymmetricCryptoOp(cipher);
+       session->setAllowMultiPartOp(true);
+       session->setAllowSinglePartOp(true);
+       session->setSymmetricKey(secretkey);
+
+       return CKR_OK;
+}
+
+// AsymAlgorithm version of C_EncryptInit
+CK_RV SoftHSM::AsymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for encryption
+       if (!key->getBooleanValue(CKA_ENCRYPT, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Get the asymmetric algorithm matching the mechanism
+       AsymMech::Type mechanism;
+       bool isRSA = false;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       mechanism = AsymMech::RSA_PKCS;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_X_509:
+                       mechanism = AsymMech::RSA;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_PKCS_OAEP:
+                       rv = MechParamCheckRSAPKCSOAEP(pMechanism);
+                       if (rv != CKR_OK)
+                               return rv;
+
+                       mechanism = AsymMech::RSA_PKCS_OAEP;
+                       isRSA = true;
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       AsymmetricAlgorithm* asymCrypto = NULL;
+       PublicKey* publicKey = NULL;
+       if (isRSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               publicKey = asymCrypto->newPublicKey();
+               if (publicKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getRSAPublicKey((RSAPublicKey*)publicKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePublicKey(publicKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+       else
+       {
+               return CKR_MECHANISM_INVALID;
+        }
+
+       session->setOpType(SESSION_OP_ENCRYPT);
+       session->setAsymmetricCryptoOp(asymCrypto);
+       session->setMechanism(mechanism);
+       session->setAllowMultiPartOp(false);
+       session->setAllowSinglePartOp(true);
+       session->setPublicKey(publicKey);
+
+       return CKR_OK;
+}
+
+// Initialise encryption using the specified object and mechanism
+CK_RV SoftHSM::C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (isSymMechanism(pMechanism))
+               return SymEncryptInit(hSession, pMechanism, hKey);
+       else
+               return AsymEncryptInit(hSession, pMechanism, hKey);
+}
+
+// SymAlgorithm version of C_Encrypt
+static CK_RV SymEncrypt(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowSinglePartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check data size
+       CK_ULONG maxSize = ulDataLen + cipher->getTagBytes();
+       if (cipher->isBlockCipher())
+       {
+               CK_ULONG remainder = ulDataLen % cipher->getBlockSize();
+               if (cipher->getPaddingMode() == false && remainder != 0)
+               {
+                       session->resetOp();
+                       return CKR_DATA_LEN_RANGE;
+               }
+
+               // Round up to block size
+               if (remainder != 0)
+               {
+                       maxSize = ulDataLen + cipher->getBlockSize() - remainder;
+               }
+               else if (cipher->getPaddingMode() == true)
+               {
+                       maxSize = ulDataLen + cipher->getBlockSize();
+               }
+       }
+       if (!cipher->checkMaximumBytes(ulDataLen))
+       {
+               session->resetOp();
+               return CKR_DATA_LEN_RANGE;
+       }
+
+       if (pEncryptedData == NULL_PTR)
+       {
+               *pulEncryptedDataLen = maxSize;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulEncryptedDataLen < maxSize)
+       {
+               *pulEncryptedDataLen = maxSize;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data(pData, ulDataLen);
+       ByteString encryptedData;
+
+       // Encrypt the data
+       if (!cipher->encryptUpdate(data, encryptedData))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Finalize encryption
+       ByteString encryptedFinal;
+       if (!cipher->encryptFinal(encryptedFinal))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       encryptedData += encryptedFinal;
+       encryptedData.resize(maxSize);
+
+       memcpy(pEncryptedData, encryptedData.byte_str(), encryptedData.size());
+       *pulEncryptedDataLen = encryptedData.size();
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// AsymAlgorithm version of C_Encrypt
+static CK_RV AsymEncrypt(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       AsymMech::Type mechanism = session->getMechanism();
+       PublicKey* publicKey = session->getPublicKey();
+       if (asymCrypto == NULL || !session->getAllowSinglePartOp() || publicKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the encrypted data
+       CK_ULONG size = publicKey->getOutputLength();
+
+       if (pEncryptedData == NULL_PTR)
+       {
+               *pulEncryptedDataLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulEncryptedDataLen < size)
+       {
+               *pulEncryptedDataLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data;
+       ByteString encryptedData;
+
+       // We must allow input length <= k and therfore need to prepend the data with zeroes.
+       if (mechanism == AsymMech::RSA) {
+               data.wipe(size-ulDataLen);
+       }
+
+       data += ByteString(pData, ulDataLen);
+
+       // Encrypt the data
+       if (!asymCrypto->encrypt(publicKey,data,encryptedData,mechanism))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (encryptedData.size() != size)
+       {
+               ERROR_MSG("The size of the encrypted data differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pEncryptedData, encryptedData.byte_str(), size);
+       *pulEncryptedDataLen = size;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Perform a single operation encryption operation in the specified session
+CK_RV SoftHSM::C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulEncryptedDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_ENCRYPT)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymEncrypt(session, pData, ulDataLen,
+                                 pEncryptedData, pulEncryptedDataLen);
+       else
+               return AsymEncrypt(session, pData, ulDataLen,
+                                  pEncryptedData, pulEncryptedDataLen);
+}
+
+// SymAlgorithm version of C_EncryptUpdate
+static CK_RV SymEncryptUpdate(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check data size
+       size_t blockSize = cipher->getBlockSize();
+       size_t remainingSize = cipher->getBufferSize();
+       CK_ULONG maxSize = ulDataLen + remainingSize;
+       if (cipher->isBlockCipher())
+       {
+               int nrOfBlocks = (ulDataLen + remainingSize) / blockSize;
+               maxSize = nrOfBlocks * blockSize;
+       }
+       if (!cipher->checkMaximumBytes(ulDataLen))
+       {
+               session->resetOp();
+               return CKR_DATA_LEN_RANGE;
+       }
+
+       // Check data size
+       if (pEncryptedData == NULL_PTR)
+       {
+               *pulEncryptedDataLen = maxSize;
+               return CKR_OK;
+       }
+
+       // Check output buffer size
+       if (*pulEncryptedDataLen < maxSize)
+       {
+               DEBUG_MSG("ulDataLen: %#5x  output buffer size: %#5x  blockSize: %#3x  remainingSize: %#4x  maxSize: %#5x",
+                         ulDataLen, *pulEncryptedDataLen, blockSize, remainingSize, maxSize);
+               *pulEncryptedDataLen = maxSize;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data(pData, ulDataLen);
+       ByteString encryptedData;
+
+       // Encrypt the data
+       if (!cipher->encryptUpdate(data, encryptedData))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       DEBUG_MSG("ulDataLen: %#5x  output buffer size: %#5x  blockSize: %#3x  remainingSize: %#4x  maxSize: %#5x  encryptedData.size(): %#5x",
+                 ulDataLen, *pulEncryptedDataLen, blockSize, remainingSize, maxSize, encryptedData.size());
+
+       // Check output size from crypto. Unrecoverable error if to large.
+       if (*pulEncryptedDataLen < encryptedData.size())
+       {
+               session->resetOp();
+               ERROR_MSG("EncryptUpdate returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.",
+                         *pulEncryptedDataLen, encryptedData.size());
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (encryptedData.size() > 0)
+       {
+               memcpy(pEncryptedData, encryptedData.byte_str(), encryptedData.size());
+       }
+       *pulEncryptedDataLen = encryptedData.size();
+
+       return CKR_OK;
+}
+
+// Feed data to the running encryption operation in a session
+CK_RV SoftHSM::C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulEncryptedDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_ENCRYPT)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymEncryptUpdate(session, pData, ulDataLen,
+                                 pEncryptedData, pulEncryptedDataLen);
+       else
+               return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// SymAlgorithm version of C_EncryptFinal
+static CK_RV SymEncryptFinal(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check data size
+       size_t remainingSize = cipher->getBufferSize() + cipher->getTagBytes();
+       CK_ULONG size = remainingSize;
+       if (cipher->isBlockCipher())
+       {
+               size_t blockSize = cipher->getBlockSize();
+               bool isPadding = cipher->getPaddingMode();
+               if ((remainingSize % blockSize) != 0 && !isPadding)
+               {
+                       session->resetOp();
+                       DEBUG_MSG("Remaining buffer size is not an integral of the block size. Block size: %#2x  Remaining size: %#2x",
+                                 blockSize, remainingSize);
+                       return CKR_DATA_LEN_RANGE;
+               }
+               // when padding: an integral of the block size that is longer than the remaining data.
+               size = isPadding ? ((remainingSize + blockSize) / blockSize) * blockSize : remainingSize;
+       }
+
+       // Give required output buffer size.
+       if (pEncryptedData == NULL_PTR)
+       {
+               *pulEncryptedDataLen = size;
+               return CKR_OK;
+       }
+
+       // Check output buffer size
+       if (*pulEncryptedDataLen < size)
+       {
+               DEBUG_MSG("output buffer size: %#5x  size: %#5x",
+                         *pulEncryptedDataLen, size);
+               *pulEncryptedDataLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Finalize encryption
+       ByteString encryptedFinal;
+       if (!cipher->encryptFinal(encryptedFinal))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       DEBUG_MSG("output buffer size: %#2x  size: %#2x  encryptedFinal.size(): %#2x",
+                 *pulEncryptedDataLen, size, encryptedFinal.size());
+
+       // Check output size from crypto. Unrecoverable error if to large.
+       if (*pulEncryptedDataLen < encryptedFinal.size())
+       {
+               session->resetOp();
+               ERROR_MSG("EncryptFinal returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.",
+                         *pulEncryptedDataLen, encryptedFinal.size());
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (encryptedFinal.size() > 0)
+       {
+               memcpy(pEncryptedData, encryptedFinal.byte_str(), encryptedFinal.size());
+       }
+       *pulEncryptedDataLen = encryptedFinal.size();
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Finalise the encryption operation
+CK_RV SoftHSM::C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_ENCRYPT) return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymEncryptFinal(session, pEncryptedData, pulEncryptedDataLen);
+       else
+               return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// SymAlgorithm version of C_DecryptInit
+CK_RV SoftHSM::SymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for decryption
+       if (!key->getBooleanValue(CKA_DECRYPT, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get the symmetric algorithm matching the mechanism
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       SymMode::Type mode = SymMode::Unknown;
+       bool padding = false;
+       ByteString iv;
+       size_t bb = 8;
+       size_t counterBits = 0;
+       ByteString aad;
+       size_t tagBytes = 0;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_DES_ECB:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES_CBC:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_DES_CBC_PAD:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+#endif
+               case CKM_DES3_ECB:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES3_CBC:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_DES3_CBC_PAD:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       bb = 7;
+                       break;
+               case CKM_AES_ECB:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::ECB;
+                       break;
+               case CKM_AES_CBC:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CBC;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       break;
+               case CKM_AES_CBC_PAD:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CBC;
+                       padding = true;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen == 0)
+                       {
+                               DEBUG_MSG("CBC mode requires an init vector");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(pMechanism->ulParameterLen);
+                       memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+                       break;
+               case CKM_AES_CTR:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CTR;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_AES_CTR_PARAMS))
+                       {
+                               DEBUG_MSG("CTR mode requires a counter block");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       counterBits = CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->ulCounterBits;
+                       if (counterBits == 0 || counterBits > 128)
+                       {
+                               DEBUG_MSG("Invalid ulCounterBits");
+                               return CKR_MECHANISM_PARAM_INVALID;
+                       }
+                       iv.resize(16);
+                       memcpy(&iv[0], CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->cb, 16);
+                       break;
+#ifdef WITH_AES_GCM
+               case CKM_AES_GCM:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::GCM;
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_GCM_PARAMS))
+                       {
+                               DEBUG_MSG("GCM mode requires parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       iv.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen);
+                       memcpy(&iv[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pIv, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen);
+                       aad.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
+                       memcpy(&aad[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pAAD, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen);
+                       tagBytes = CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulTagBits;
+                       if (tagBytes > 128 || tagBytes % 8 != 0)
+                       {
+                               DEBUG_MSG("Invalid ulTagBits value");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       tagBytes = tagBytes / 8;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* secretkey = new SymmetricKey();
+
+       if (getSymmetricKey(secretkey, token, key) != CKR_OK)
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // adjust key bit length
+       secretkey->setBitLen(secretkey->getKeyBits().size() * bb);
+
+       // Initialize decryption
+       if (!cipher->decryptInit(secretkey, mode, iv, padding, counterBits, aad, tagBytes))
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       session->setOpType(SESSION_OP_DECRYPT);
+       session->setSymmetricCryptoOp(cipher);
+       session->setAllowMultiPartOp(true);
+       session->setAllowSinglePartOp(true);
+       session->setSymmetricKey(secretkey);
+
+       return CKR_OK;
+}
+
+// AsymAlgorithm version of C_DecryptInit
+CK_RV SoftHSM::AsymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for decryption
+       if (!key->getBooleanValue(CKA_DECRYPT, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get the asymmetric algorithm matching the mechanism
+       AsymMech::Type mechanism = AsymMech::Unknown;
+       bool isRSA = false;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       mechanism = AsymMech::RSA_PKCS;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_X_509:
+                       mechanism = AsymMech::RSA;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_PKCS_OAEP:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS))
+                       {
+                               DEBUG_MSG("pParameter must be of type CK_RSA_PKCS_OAEP_PARAMS");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1)
+                       {
+                               DEBUG_MSG("hashAlg must be CKM_SHA_1");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1)
+                       {
+                               DEBUG_MSG("mgf must be CKG_MGF1_SHA1");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+
+                       mechanism = AsymMech::RSA_PKCS_OAEP;
+                       isRSA = true;
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       AsymmetricAlgorithm* asymCrypto = NULL;
+       PrivateKey* privateKey = NULL;
+       if (isRSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+       else
+       {
+               return CKR_MECHANISM_INVALID;
+        }
+
+       // Check if re-authentication is required
+       if (key->getBooleanValue(CKA_ALWAYS_AUTHENTICATE, false))
+       {
+               session->setReAuthentication(true);
+       }
+
+       session->setOpType(SESSION_OP_DECRYPT);
+       session->setAsymmetricCryptoOp(asymCrypto);
+       session->setMechanism(mechanism);
+       session->setAllowMultiPartOp(false);
+       session->setAllowSinglePartOp(true);
+       session->setPrivateKey(privateKey);
+
+       return CKR_OK;
+}
+
+// Initialise decryption using the specified object
+CK_RV SoftHSM::C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (isSymMechanism(pMechanism))
+               return SymDecryptInit(hSession, pMechanism, hKey);
+       else
+               return AsymDecryptInit(hSession, pMechanism, hKey);
+}
+
+// SymAlgorithm version of C_Decrypt
+static CK_RV SymDecrypt(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowSinglePartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check encrypted data size
+       if (cipher->isBlockCipher() && ulEncryptedDataLen % cipher->getBlockSize() != 0)
+       {
+               session->resetOp();
+               return CKR_ENCRYPTED_DATA_LEN_RANGE;
+       }
+       if (!cipher->checkMaximumBytes(ulEncryptedDataLen))
+       {
+               session->resetOp();
+               return CKR_ENCRYPTED_DATA_LEN_RANGE;
+       }
+
+       if (pData == NULL_PTR)
+       {
+               *pulDataLen = ulEncryptedDataLen;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulDataLen < ulEncryptedDataLen)
+       {
+               *pulDataLen = ulEncryptedDataLen;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString encryptedData(pEncryptedData, ulEncryptedDataLen);
+       ByteString data;
+
+       // Decrypt the data
+       if (!cipher->decryptUpdate(encryptedData,data))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Finalize decryption
+       ByteString dataFinal;
+       if (!cipher->decryptFinal(dataFinal))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       data += dataFinal;
+       if (data.size() > ulEncryptedDataLen)
+       {
+               data.resize(ulEncryptedDataLen);
+       }
+
+       if (data.size() != 0)
+       {
+               memcpy(pData, data.byte_str(), data.size());
+       }
+       *pulDataLen = data.size();
+
+       session->resetOp();
+       return CKR_OK;
+
+}
+
+// AsymAlgorithm version of C_Decrypt
+static CK_RV AsymDecrypt(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       AsymMech::Type mechanism = session->getMechanism();
+       PrivateKey* privateKey = session->getPrivateKey();
+       if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check if re-authentication is required
+       if (session->getReAuthentication())
+       {
+               session->resetOp();
+               return CKR_USER_NOT_LOGGED_IN;
+       }
+
+       // Size of the data
+       CK_ULONG size = privateKey->getOutputLength();
+       if (pData == NULL_PTR)
+       {
+               *pulDataLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulDataLen < size)
+       {
+               *pulDataLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString encryptedData(pEncryptedData, ulEncryptedDataLen);
+       ByteString data;
+
+       // Decrypt the data
+       if (!asymCrypto->decrypt(privateKey,encryptedData,data,mechanism))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (data.size() > size)
+       {
+               ERROR_MSG("The size of the decrypted data exceeds the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       if (data.size() != 0)
+       {
+               memcpy(pData, data.byte_str(), data.size());
+       }
+       *pulDataLen = data.size();
+
+       session->resetOp();
+       return CKR_OK;
+
+}
+
+// Perform a single operation decryption in the given session
+CK_RV SoftHSM::C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pEncryptedData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DECRYPT)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymDecrypt(session, pEncryptedData, ulEncryptedDataLen,
+                                 pData, pulDataLen);
+       else
+               return AsymDecrypt(session, pEncryptedData, ulEncryptedDataLen,
+                                  pData, pulDataLen);
+}
+
+// SymAlgorithm version of C_DecryptUpdate
+static CK_RV SymDecryptUpdate(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check encrypted data size
+       size_t blockSize = cipher->getBlockSize();
+       size_t remainingSize = cipher->getBufferSize();
+       CK_ULONG maxSize = ulEncryptedDataLen + remainingSize;
+       if (cipher->isBlockCipher())
+       {
+               // There must always be one block left in padding mode if next operation is DecryptFinal.
+               // To guarantee that one byte is removed in padding mode when the number of blocks is calculated.
+               size_t paddingAdjustByte = cipher->getPaddingMode() ? 1 : 0;
+               int nrOfBlocks = (ulEncryptedDataLen + remainingSize - paddingAdjustByte) / blockSize;
+               maxSize = nrOfBlocks * blockSize;
+       }
+       if (!cipher->checkMaximumBytes(ulEncryptedDataLen))
+       {
+               session->resetOp();
+               return CKR_ENCRYPTED_DATA_LEN_RANGE;
+       }
+
+       // Give required output buffer size.
+       if (pData == NULL_PTR)
+       {
+               *pDataLen = maxSize;
+               return CKR_OK;
+       }
+
+       // Check output buffer size
+       if (*pDataLen < maxSize)
+       {
+               DEBUG_MSG("Output buffer too short   ulEncryptedDataLen: %#5x  output buffer size: %#5x  blockSize: %#3x  remainingSize: %#4x  maxSize: %#5x",
+                         ulEncryptedDataLen, *pDataLen, blockSize, remainingSize, maxSize);
+               *pDataLen = maxSize;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data(pEncryptedData, ulEncryptedDataLen);
+       ByteString decryptedData;
+
+       // Encrypt the data
+       if (!cipher->decryptUpdate(data, decryptedData))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       DEBUG_MSG("ulEncryptedDataLen: %#5x  output buffer size: %#5x  blockSize: %#3x  remainingSize: %#4x  maxSize: %#5x  decryptedData.size(): %#5x",
+                 ulEncryptedDataLen, *pDataLen, blockSize, remainingSize, maxSize, decryptedData.size());
+
+       // Check output size from crypto. Unrecoverable error if to large.
+       if (*pDataLen < decryptedData.size())
+       {
+               session->resetOp();
+               ERROR_MSG("DecryptUpdate returning too much data. Length of output data buffer is %i but %i bytes was returned by the decrypt.",
+                               *pDataLen, decryptedData.size());
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (decryptedData.size() > 0)
+       {
+               memcpy(pData, decryptedData.byte_str(), decryptedData.size());
+       }
+       *pDataLen = decryptedData.size();
+
+       return CKR_OK;
+}
+
+
+// Feed data to the running decryption operation in a session
+CK_RV SoftHSM::C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pEncryptedData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DECRYPT)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymDecryptUpdate(session, pEncryptedData, ulEncryptedDataLen,
+                                 pData, pDataLen);
+       else
+               return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+static CK_RV SymDecryptFinal(Session* session, CK_BYTE_PTR pDecryptedData, CK_ULONG_PTR pulDecryptedDataLen)
+{
+       SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp();
+       if (cipher == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check encrypted data size
+       size_t remainingSize = cipher->getBufferSize();
+       CK_ULONG size = remainingSize;
+       if (cipher->isBlockCipher())
+       {
+               size_t blockSize = cipher->getBlockSize();
+               if (remainingSize % blockSize != 0)
+               {
+                       session->resetOp();
+                       DEBUG_MSG("Remaining data length is not an integral of the block size. Block size: %#2x  Remaining size: %#2x",
+                                  blockSize, remainingSize);
+                       return CKR_ENCRYPTED_DATA_LEN_RANGE;
+               }
+               // It is at least one padding byte. If no padding the all remains will be returned.
+               size_t paddingAdjustByte = cipher->getPaddingMode() ? 1 : 0;
+               size = remainingSize - paddingAdjustByte;
+       }
+
+       // Give required output buffer size.
+       if (pDecryptedData == NULL_PTR)
+       {
+               *pulDecryptedDataLen = size;
+               return CKR_OK;
+       }
+
+       // Check output buffer size
+       if (*pulDecryptedDataLen < size)
+       {
+               DEBUG_MSG("output buffer size: %#5x  size: %#5x",
+                         *pulDecryptedDataLen, size);
+               *pulDecryptedDataLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Finalize decryption
+       ByteString decryptedFinal;
+       if (!cipher->decryptFinal(decryptedFinal))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       DEBUG_MSG("output buffer size: %#2x  size: %#2x  decryptedFinal.size(): %#2x",
+                 *pulDecryptedDataLen, size, decryptedFinal.size());
+
+       // Check output size from crypto. Unrecoverable error if to large.
+       if (*pulDecryptedDataLen < decryptedFinal.size())
+       {
+               session->resetOp();
+               ERROR_MSG("DecryptFinal returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.",
+                         *pulDecryptedDataLen, decryptedFinal.size());
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (decryptedFinal.size() > 0)
+       {
+               memcpy(pDecryptedData, decryptedFinal.byte_str(), decryptedFinal.size());
+       }
+       *pulDecryptedDataLen = decryptedFinal.size();
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Finalise the decryption operation
+CK_RV SoftHSM::C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DECRYPT) return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getSymmetricCryptoOp() != NULL)
+               return SymDecryptFinal(session, pData, pDataLen);
+       else
+               return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Initialise digesting using the specified mechanism in the specified session
+CK_RV SoftHSM::C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the mechanism
+       HashAlgo::Type algo = HashAlgo::Unknown;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_MD5:
+                       algo = HashAlgo::MD5;
+                       break;
+#endif
+               case CKM_SHA_1:
+                       algo = HashAlgo::SHA1;
+                       break;
+               case CKM_SHA224:
+                       algo = HashAlgo::SHA224;
+                       break;
+               case CKM_SHA256:
+                       algo = HashAlgo::SHA256;
+                       break;
+               case CKM_SHA384:
+                       algo = HashAlgo::SHA384;
+                       break;
+               case CKM_SHA512:
+                       algo = HashAlgo::SHA512;
+                       break;
+#ifdef WITH_GOST
+               case CKM_GOSTR3411:
+                       algo = HashAlgo::GOST;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(algo);
+       if (hash == NULL) return CKR_MECHANISM_INVALID;
+
+       // Initialize hashing
+       if (hash->hashInit() == false)
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+               return CKR_GENERAL_ERROR;
+       }
+
+       session->setOpType(SESSION_OP_DIGEST);
+       session->setDigestOp(hash);
+       session->setHashAlgo(algo);
+
+       return CKR_OK;
+}
+
+// Digest the specified data in a one-pass operation and return the resulting digest
+CK_RV SoftHSM::C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pulDigestLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED;
+
+       // Return size
+       CK_ULONG size = session->getDigestOp()->getHashSize();
+       if (pDigest == NULL_PTR)
+       {
+               *pulDigestLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulDigestLen < size)
+       {
+               *pulDigestLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data(pData, ulDataLen);
+
+       // Digest the data
+       if (session->getDigestOp()->hashUpdate(data) == false)
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Get the digest
+       ByteString digest;
+       if (session->getDigestOp()->hashFinal(digest) == false)
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (digest.size() != size)
+       {
+               ERROR_MSG("The size of the digest differ from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pDigest, digest.byte_str(), size);
+       *pulDigestLen = size;
+
+       session->resetOp();
+
+       return CKR_OK;
+}
+
+// Update a running digest operation
+CK_RV SoftHSM::C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED;
+
+       // Get the data
+       ByteString data(pPart, ulPartLen);
+
+       // Digest the data
+       if (session->getDigestOp()->hashUpdate(data) == false)
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+// Update a running digest operation by digesting a secret key with the specified handle
+CK_RV SoftHSM::C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hObject);
+       if (key == NULL_PTR || !key->isValid()) return CKR_KEY_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               // CKR_USER_NOT_LOGGED_IN is not a valid return code for this function,
+               // so we use CKR_GENERAL_ERROR.
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Whitelist
+       HashAlgo::Type algo = session->getHashAlgo();
+       if (algo != HashAlgo::SHA1 &&
+           algo != HashAlgo::SHA224 &&
+           algo != HashAlgo::SHA256 &&
+           algo != HashAlgo::SHA384 &&
+           algo != HashAlgo::SHA512)
+       {
+               // Parano...
+               if (!key->getBooleanValue(CKA_EXTRACTABLE, false))
+                       return CKR_KEY_INDIGESTIBLE;
+               if (key->getBooleanValue(CKA_SENSITIVE, false))
+                       return CKR_KEY_INDIGESTIBLE;
+       }
+
+       // Get value
+       if (!key->attributeExists(CKA_VALUE))
+               return CKR_KEY_INDIGESTIBLE;
+       ByteString keybits;
+       if (isPrivate)
+       {
+               if (!token->decrypt(key->getByteStringValue(CKA_VALUE), keybits))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               keybits = key->getByteStringValue(CKA_VALUE);
+       }
+
+       // Digest the value
+       if (session->getDigestOp()->hashUpdate(keybits) == false)
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+// Finalise the digest operation in the specified session and return the digest
+CK_RV SoftHSM::C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pulDigestLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED;
+
+       // Return size
+       CK_ULONG size = session->getDigestOp()->getHashSize();
+       if (pDigest == NULL_PTR)
+       {
+               *pulDigestLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulDigestLen < size)
+       {
+               *pulDigestLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the digest
+       ByteString digest;
+       if (session->getDigestOp()->hashFinal(digest) == false)
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (digest.size() != size)
+       {
+               ERROR_MSG("The size of the digest differ from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pDigest, digest.byte_str(), size);
+       *pulDigestLen = size;
+
+       session->resetOp();
+
+       return CKR_OK;
+}
+
+// Sign*/Verify*() is for MACs too
+static bool isMacMechanism(CK_MECHANISM_PTR pMechanism)
+{
+       if (pMechanism == NULL_PTR) return false;
+
+       switch(pMechanism->mechanism) {
+               case CKM_MD5_HMAC:
+               case CKM_SHA_1_HMAC:
+               case CKM_SHA224_HMAC:
+               case CKM_SHA256_HMAC:
+               case CKM_SHA384_HMAC:
+               case CKM_SHA512_HMAC:
+#ifdef WITH_GOST
+               case CKM_GOSTR3411_HMAC:
+#endif
+               case CKM_DES3_CMAC:
+               case CKM_AES_CMAC:
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+// MacAlgorithm version of C_SignInit
+CK_RV SoftHSM::MacSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for signing
+       if (!key->getBooleanValue(CKA_SIGN, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get key info
+       CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED);
+
+       // Get the MAC algorithm matching the mechanism
+       // Also check mechanism constraints
+       MacAlgo::Type algo = MacAlgo::Unknown;
+       size_t bb = 8;
+       size_t minSize = 0;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_MD5_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_MD5_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 16;
+                       algo = MacAlgo::HMAC_MD5;
+                       break;
+#endif
+               case CKM_SHA_1_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA_1_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 20;
+                       algo = MacAlgo::HMAC_SHA1;
+                       break;
+               case CKM_SHA224_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA224_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 28;
+                       algo = MacAlgo::HMAC_SHA224;
+                       break;
+               case CKM_SHA256_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA256_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 32;
+                       algo = MacAlgo::HMAC_SHA256;
+                       break;
+               case CKM_SHA384_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA384_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 48;
+                       algo = MacAlgo::HMAC_SHA384;
+                       break;
+               case CKM_SHA512_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA512_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 64;
+                       algo = MacAlgo::HMAC_SHA512;
+                       break;
+#ifdef WITH_GOST
+               case CKM_GOSTR3411_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_GOST28147)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 32;
+                       algo = MacAlgo::HMAC_GOST;
+                       break;
+#endif
+               case CKM_DES3_CMAC:
+                       if (keyType != CKK_DES2 && keyType != CKK_DES3)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       algo = MacAlgo::CMAC_DES;
+                       bb = 7;
+                       break;
+               case CKM_AES_CMAC:
+                       if (keyType != CKK_AES)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       algo = MacAlgo::CMAC_AES;
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       MacAlgorithm* mac = CryptoFactory::i()->getMacAlgorithm(algo);
+       if (mac == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* privkey = new SymmetricKey();
+
+       if (getSymmetricKey(privkey, token, key) != CKR_OK)
+       {
+               mac->recycleKey(privkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Adjust key bit length
+       privkey->setBitLen(privkey->getKeyBits().size() * bb);
+
+       // Check key size
+       if (privkey->getBitLen() < (minSize*8))
+       {
+               mac->recycleKey(privkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_KEY_SIZE_RANGE;
+       }
+
+       // Initialize signing
+       if (!mac->signInit(privkey))
+       {
+               mac->recycleKey(privkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       session->setOpType(SESSION_OP_SIGN);
+       session->setMacOp(mac);
+       session->setAllowMultiPartOp(true);
+       session->setAllowSinglePartOp(true);
+       session->setSymmetricKey(privkey);
+
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_SignInit
+CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for signing
+       if (!key->getBooleanValue(CKA_SIGN, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get the asymmetric algorithm matching the mechanism
+       AsymMech::Type mechanism = AsymMech::Unknown;
+       void* param = NULL;
+       size_t paramLen = 0;
+       RSA_PKCS_PSS_PARAMS pssParam;
+       bool bAllowMultiPartOp;
+       bool isRSA = false;
+       bool isDSA = false;
+       bool isECDSA = false;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       mechanism = AsymMech::RSA_PKCS;
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_X_509:
+                       mechanism = AsymMech::RSA;
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_MD5_RSA_PKCS:
+                       mechanism = AsymMech::RSA_MD5_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+#endif
+               case CKM_SHA1_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA1_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA224_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA224_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA256_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA256_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA384_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA384_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA512_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA512_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+#ifdef WITH_RAW_PSS
+               case CKM_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS))
+                       {
+                               ERROR_MSG("Invalid RSA-PSS parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_PKCS_PSS;
+                       unsigned long allowedMgf;
+
+                       switch(CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg) {
+                               case CKM_SHA_1:
+                                       pssParam.hashAlg = HashAlgo::SHA1;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA1;
+                                       allowedMgf = CKG_MGF1_SHA1;
+                                       break;
+                               case CKM_SHA224:
+                                       pssParam.hashAlg = HashAlgo::SHA224;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA224;
+                                       allowedMgf = CKG_MGF1_SHA224;
+                                       break;
+                               case CKM_SHA256:
+                                       pssParam.hashAlg = HashAlgo::SHA256;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA256;
+                                       allowedMgf = CKG_MGF1_SHA256;
+                                       break;
+                               case CKM_SHA384:
+                                       pssParam.hashAlg = HashAlgo::SHA384;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA384;
+                                       allowedMgf = CKG_MGF1_SHA384;
+                                       break;
+                               case CKM_SHA512:
+                                       pssParam.hashAlg = HashAlgo::SHA512;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA512;
+                                       allowedMgf = CKG_MGF1_SHA512;
+                                       break;
+                               default:
+                                       ERROR_MSG("Invalid RSA-PSS hash");
+                                       return CKR_ARGUMENTS_BAD;
+                       }
+
+                       if (CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != allowedMgf) {
+                               ERROR_MSG("Hash and MGF don't match");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+#endif
+               case CKM_SHA1_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA1_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA1;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA1;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA224_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA224 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA224_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA224;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA224;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA256_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA256 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA256_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA256;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA256;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA384_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA384 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA384_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA384;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA384;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA512_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA512 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA512_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA512;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA512;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_DSA:
+                       mechanism = AsymMech::DSA;
+                       bAllowMultiPartOp = false;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA1:
+                       mechanism = AsymMech::DSA_SHA1;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA224:
+                       mechanism = AsymMech::DSA_SHA224;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA256:
+                       mechanism = AsymMech::DSA_SHA256;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA384:
+                       mechanism = AsymMech::DSA_SHA384;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA512:
+                       mechanism = AsymMech::DSA_SHA512;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+#ifdef WITH_ECC
+               case CKM_ECDSA:
+                       mechanism = AsymMech::ECDSA;
+                       bAllowMultiPartOp = false;
+                       isECDSA = true;
+                       break;
+#endif
+#ifdef WITH_GOST
+               case CKM_GOSTR3410:
+                       mechanism = AsymMech::GOST;
+                       bAllowMultiPartOp = false;
+                       break;
+               case CKM_GOSTR3410_WITH_GOSTR3411:
+                       mechanism = AsymMech::GOST_GOST;
+                       bAllowMultiPartOp = true;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       AsymmetricAlgorithm* asymCrypto = NULL;
+       PrivateKey* privateKey = NULL;
+       if (isRSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+       else if (isDSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getDSAPrivateKey((DSAPrivateKey*)privateKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+        }
+#ifdef WITH_ECC
+       else if (isECDSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getECPrivateKey((ECPrivateKey*)privateKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+#endif
+       else
+       {
+#ifdef WITH_GOST
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getGOSTPrivateKey((GOSTPrivateKey*)privateKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+#else
+               return CKR_MECHANISM_INVALID;
+#endif
+        }
+
+       // Initialize signing
+       if (bAllowMultiPartOp && !asymCrypto->signInit(privateKey,mechanism,param,paramLen))
+       {
+               asymCrypto->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       // Check if re-authentication is required
+       if (key->getBooleanValue(CKA_ALWAYS_AUTHENTICATE, false))
+       {
+               session->setReAuthentication(true);
+       }
+
+       session->setOpType(SESSION_OP_SIGN);
+       session->setAsymmetricCryptoOp(asymCrypto);
+       session->setMechanism(mechanism);
+       session->setParameters(param, paramLen);
+       session->setAllowMultiPartOp(bAllowMultiPartOp);
+       session->setAllowSinglePartOp(true);
+       session->setPrivateKey(privateKey);
+
+       return CKR_OK;
+}
+
+// Initialise a signing operation using the specified key and mechanism
+CK_RV SoftHSM::C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (isMacMechanism(pMechanism))
+               return MacSignInit(hSession, pMechanism, hKey);
+       else
+               return AsymSignInit(hSession, pMechanism, hKey);
+}
+
+// MacAlgorithm version of C_Sign
+static CK_RV MacSign(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL || !session->getAllowSinglePartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = mac->getMacSize();
+       if (pSignature == NULL_PTR)
+       {
+               *pulSignatureLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulSignatureLen < size)
+       {
+               *pulSignatureLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data(pData, ulDataLen);
+
+       // Sign the data
+       if (!mac->signUpdate(data))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Get the signature
+       ByteString signature;
+       if (!mac->signFinal(signature))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (signature.size() != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pSignature, signature.byte_str(), size);
+       *pulSignatureLen = size;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_Sign
+static CK_RV AsymSign(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       AsymMech::Type mechanism = session->getMechanism();
+       PrivateKey* privateKey = session->getPrivateKey();
+       size_t paramLen;
+       void* param = session->getParameters(paramLen);
+       if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check if re-authentication is required
+       if (session->getReAuthentication())
+       {
+               session->resetOp();
+               return CKR_USER_NOT_LOGGED_IN;
+       }
+
+       // Size of the signature
+       CK_ULONG size = privateKey->getOutputLength();
+       if (pSignature == NULL_PTR)
+       {
+               *pulSignatureLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulSignatureLen < size)
+       {
+               *pulSignatureLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the data
+       ByteString data;
+
+       // We must allow input length <= k and therfore need to prepend the data with zeroes.
+       if (mechanism == AsymMech::RSA) {
+               data.wipe(size-ulDataLen);
+       }
+
+       data += ByteString(pData, ulDataLen);
+       ByteString signature;
+
+       // Sign the data
+       if (session->getAllowMultiPartOp())
+       {
+               if (!asymCrypto->signUpdate(data) ||
+                   !asymCrypto->signFinal(signature))
+               {
+                       session->resetOp();
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+       else if (!asymCrypto->sign(privateKey,data,signature,mechanism,param,paramLen))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (signature.size() != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pSignature, signature.byte_str(), size);
+       *pulSignatureLen = size;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Sign the data in a single pass operation
+CK_RV SoftHSM::C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulSignatureLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_SIGN)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacSign(session, pData, ulDataLen,
+                              pSignature, pulSignatureLen);
+       else
+               return AsymSign(session, pData, ulDataLen,
+                               pSignature, pulSignatureLen);
+}
+
+// MacAlgorithm version of C_SignUpdate
+static CK_RV MacSignUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Get the part
+       ByteString part(pPart, ulPartLen);
+
+       // Sign the data
+       if (!mac->signUpdate(part))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       session->setAllowSinglePartOp(false);
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_SignUpdate
+static CK_RV AsymSignUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       if (asymCrypto == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check if re-authentication is required
+       if (session->getReAuthentication())
+       {
+               session->resetOp();
+               return CKR_USER_NOT_LOGGED_IN;
+       }
+
+       // Get the part
+       ByteString part(pPart, ulPartLen);
+
+       // Sign the data
+       if (!asymCrypto->signUpdate(part))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       session->setAllowSinglePartOp(false);
+       return CKR_OK;
+}
+
+// Update a running signing operation with additional data
+CK_RV SoftHSM::C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_SIGN)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacSignUpdate(session, pPart, ulPartLen);
+       else
+               return AsymSignUpdate(session, pPart, ulPartLen);
+}
+
+// MacAlgorithm version of C_SignFinal
+static CK_RV MacSignFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = mac->getMacSize();
+       if (pSignature == NULL_PTR)
+       {
+               *pulSignatureLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulSignatureLen < size)
+       {
+               *pulSignatureLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the signature
+       ByteString signature;
+       if (!mac->signFinal(signature))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (signature.size() != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pSignature, signature.byte_str(), size);
+       *pulSignatureLen = size;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_SignFinal
+static CK_RV AsymSignFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       PrivateKey* privateKey = session->getPrivateKey();
+       if (asymCrypto == NULL || privateKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Check if re-authentication is required
+       if (session->getReAuthentication())
+       {
+               session->resetOp();
+               return CKR_USER_NOT_LOGGED_IN;
+       }
+
+       // Size of the signature
+       CK_ULONG size = privateKey->getOutputLength();
+       if (pSignature == NULL_PTR)
+       {
+               *pulSignatureLen = size;
+               return CKR_OK;
+       }
+
+       // Check buffer size
+       if (*pulSignatureLen < size)
+       {
+               *pulSignatureLen = size;
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       // Get the signature
+       ByteString signature;
+       if (!asymCrypto->signFinal(signature))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Check size
+       if (signature.size() != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+       memcpy(pSignature, signature.byte_str(), size);
+       *pulSignatureLen = size;
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Finalise a running signing operation and return the signature
+CK_RV SoftHSM::C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pulSignatureLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_SIGN || !session->getAllowMultiPartOp())
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacSignFinal(session, pSignature, pulSignatureLen);
+       else
+               return AsymSignFinal(session, pSignature, pulSignatureLen);
+}
+
+// Initialise a signing operation that allows recovery of the signed data
+CK_RV SoftHSM::C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR /*pMechanism*/, CK_OBJECT_HANDLE /*hKey*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Perform a single part signing operation that allows recovery of the signed data
+CK_RV SoftHSM::C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pData*/, CK_ULONG /*ulDataLen*/, CK_BYTE_PTR /*pSignature*/, CK_ULONG_PTR /*pulSignatureLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// MacAlgorithm version of C_VerifyInit
+CK_RV SoftHSM::MacVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for verifying
+       if (!key->getBooleanValue(CKA_VERIFY, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get key info
+       CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED);
+
+       // Get the MAC algorithm matching the mechanism
+       // Also check mechanism constraints
+       MacAlgo::Type algo = MacAlgo::Unknown;
+       size_t bb = 8;
+       size_t minSize = 0;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_MD5_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_MD5_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 16;
+                       algo = MacAlgo::HMAC_MD5;
+                       break;
+#endif
+               case CKM_SHA_1_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA_1_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 20;
+                       algo = MacAlgo::HMAC_SHA1;
+                       break;
+               case CKM_SHA224_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA224_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 28;
+                       algo = MacAlgo::HMAC_SHA224;
+                       break;
+               case CKM_SHA256_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA256_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 32;
+                       algo = MacAlgo::HMAC_SHA256;
+                       break;
+               case CKM_SHA384_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA384_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 48;
+                       algo = MacAlgo::HMAC_SHA384;
+                       break;
+               case CKM_SHA512_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA512_HMAC)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 64;
+                       algo = MacAlgo::HMAC_SHA512;
+                       break;
+#ifdef WITH_GOST
+               case CKM_GOSTR3411_HMAC:
+                       if (keyType != CKK_GENERIC_SECRET && keyType != CKK_GOST28147)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       minSize = 32;
+                       algo = MacAlgo::HMAC_GOST;
+                       break;
+#endif
+               case CKM_DES3_CMAC:
+                       if (keyType != CKK_DES2 && keyType != CKK_DES3)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       algo = MacAlgo::CMAC_DES;
+                       bb = 7;
+                       break;
+               case CKM_AES_CMAC:
+                       if (keyType != CKK_AES)
+                               return CKR_KEY_TYPE_INCONSISTENT;
+                       algo = MacAlgo::CMAC_AES;
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       MacAlgorithm* mac = CryptoFactory::i()->getMacAlgorithm(algo);
+       if (mac == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* pubkey = new SymmetricKey();
+
+       if (getSymmetricKey(pubkey, token, key) != CKR_OK)
+       {
+               mac->recycleKey(pubkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Adjust key bit length
+       pubkey->setBitLen(pubkey->getKeyBits().size() * bb);
+
+       // Check key size
+       if (pubkey->getBitLen() < (minSize*8))
+       {
+               mac->recycleKey(pubkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_KEY_SIZE_RANGE;
+       }
+
+       // Initialize verifying
+       if (!mac->verifyInit(pubkey))
+       {
+               mac->recycleKey(pubkey);
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       session->setOpType(SESSION_OP_VERIFY);
+       session->setMacOp(mac);
+       session->setAllowMultiPartOp(true);
+       session->setAllowSinglePartOp(true);
+       session->setSymmetricKey(pubkey);
+
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_VerifyInit
+CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check read user credentials
+       CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for verifying
+       if (!key->getBooleanValue(CKA_VERIFY, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Get the asymmetric algorithm matching the mechanism
+       AsymMech::Type mechanism = AsymMech::Unknown;
+       void* param = NULL;
+       size_t paramLen = 0;
+       RSA_PKCS_PSS_PARAMS pssParam;
+       bool bAllowMultiPartOp;
+       bool isRSA = false;
+       bool isDSA = false;
+       bool isECDSA = false;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       mechanism = AsymMech::RSA_PKCS;
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+               case CKM_RSA_X_509:
+                       mechanism = AsymMech::RSA;
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_MD5_RSA_PKCS:
+                       mechanism = AsymMech::RSA_MD5_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+#endif
+               case CKM_SHA1_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA1_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA224_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA224_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA256_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA256_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA384_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA384_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA512_RSA_PKCS:
+                       mechanism = AsymMech::RSA_SHA512_PKCS;
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+#ifdef WITH_RAW_PSS
+               case CKM_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS))
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_PKCS_PSS;
+
+                       unsigned long expectedMgf;
+                       switch(CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg) {
+                               case CKM_SHA_1:
+                                       pssParam.hashAlg = HashAlgo::SHA1;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA1;
+                                       expectedMgf = CKG_MGF1_SHA1;
+                                       break;
+                               case CKM_SHA224:
+                                       pssParam.hashAlg = HashAlgo::SHA224;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA224;
+                                       expectedMgf = CKG_MGF1_SHA224;
+                                       break;
+                               case CKM_SHA256:
+                                       pssParam.hashAlg = HashAlgo::SHA256;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA256;
+                                       expectedMgf = CKG_MGF1_SHA256;
+                                       break;
+                               case CKM_SHA384:
+                                       pssParam.hashAlg = HashAlgo::SHA384;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA384;
+                                       expectedMgf = CKG_MGF1_SHA384;
+                                       break;
+                               case CKM_SHA512:
+                                       pssParam.hashAlg = HashAlgo::SHA512;
+                                       pssParam.mgf = AsymRSAMGF::MGF1_SHA512;
+                                       expectedMgf = CKG_MGF1_SHA512;
+                                       break;
+                               default:
+                                       return CKR_ARGUMENTS_BAD;
+                       }
+
+                       if (CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != expectedMgf) {
+                               return CKR_ARGUMENTS_BAD;
+                       }
+
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = false;
+                       isRSA = true;
+                       break;
+#endif
+               case CKM_SHA1_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA1_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA1;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA1;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA224_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA224 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA224_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA224;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA224;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA256_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA256 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA256_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA256;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA256;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA384_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA384 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA384_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA384;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA384;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_SHA512_RSA_PKCS_PSS:
+                       if (pMechanism->pParameter == NULL_PTR ||
+                           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA512 ||
+                           CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               return CKR_ARGUMENTS_BAD;
+                       }
+                       mechanism = AsymMech::RSA_SHA512_PKCS_PSS;
+                       pssParam.hashAlg = HashAlgo::SHA512;
+                       pssParam.mgf = AsymRSAMGF::MGF1_SHA512;
+                       pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen;
+                       param = &pssParam;
+                       paramLen = sizeof(pssParam);
+                       bAllowMultiPartOp = true;
+                       isRSA = true;
+                       break;
+               case CKM_DSA:
+                       mechanism = AsymMech::DSA;
+                       bAllowMultiPartOp = false;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA1:
+                       mechanism = AsymMech::DSA_SHA1;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA224:
+                       mechanism = AsymMech::DSA_SHA224;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA256:
+                       mechanism = AsymMech::DSA_SHA256;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA384:
+                       mechanism = AsymMech::DSA_SHA384;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+               case CKM_DSA_SHA512:
+                       mechanism = AsymMech::DSA_SHA512;
+                       bAllowMultiPartOp = true;
+                       isDSA = true;
+                       break;
+#ifdef WITH_ECC
+               case CKM_ECDSA:
+                       mechanism = AsymMech::ECDSA;
+                       bAllowMultiPartOp = false;
+                       isECDSA = true;
+                       break;
+#endif
+#ifdef WITH_GOST
+               case CKM_GOSTR3410:
+                       mechanism = AsymMech::GOST;
+                       bAllowMultiPartOp = false;
+                       break;
+               case CKM_GOSTR3410_WITH_GOSTR3411:
+                       mechanism = AsymMech::GOST_GOST;
+                       bAllowMultiPartOp = true;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       AsymmetricAlgorithm* asymCrypto = NULL;
+       PublicKey* publicKey = NULL;
+       if (isRSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               publicKey = asymCrypto->newPublicKey();
+               if (publicKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getRSAPublicKey((RSAPublicKey*)publicKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePublicKey(publicKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+       else if (isDSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               publicKey = asymCrypto->newPublicKey();
+               if (publicKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getDSAPublicKey((DSAPublicKey*)publicKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePublicKey(publicKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+        }
+#ifdef WITH_ECC
+       else if (isECDSA)
+       {
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               publicKey = asymCrypto->newPublicKey();
+               if (publicKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getECPublicKey((ECPublicKey*)publicKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePublicKey(publicKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+#endif
+       else
+       {
+#ifdef WITH_GOST
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST);
+               if (asymCrypto == NULL) return CKR_MECHANISM_INVALID;
+
+               publicKey = asymCrypto->newPublicKey();
+               if (publicKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+
+               if (getGOSTPublicKey((GOSTPublicKey*)publicKey, token, key) != CKR_OK)
+               {
+                       asymCrypto->recyclePublicKey(publicKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+#else
+               return CKR_MECHANISM_INVALID;
+#endif
+        }
+
+       // Initialize verifying
+       if (bAllowMultiPartOp && !asymCrypto->verifyInit(publicKey,mechanism,param,paramLen))
+       {
+               asymCrypto->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       session->setOpType(SESSION_OP_VERIFY);
+       session->setAsymmetricCryptoOp(asymCrypto);
+       session->setMechanism(mechanism);
+       session->setParameters(param, paramLen);
+       session->setAllowMultiPartOp(bAllowMultiPartOp);
+       session->setAllowSinglePartOp(true);
+       session->setPublicKey(publicKey);
+
+       return CKR_OK;
+}
+
+// Initialise a verification operation using the specified key and mechanism
+CK_RV SoftHSM::C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       if (isMacMechanism(pMechanism))
+               return MacVerifyInit(hSession, pMechanism, hKey);
+       else
+               return AsymVerifyInit(hSession, pMechanism, hKey);
+}
+
+// MacAlgorithm version of C_Verify
+static CK_RV MacVerify(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL || !session->getAllowSinglePartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = mac->getMacSize();
+
+       // Check buffer size
+       if (ulSignatureLen != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_SIGNATURE_LEN_RANGE;
+       }
+
+       // Get the data
+       ByteString data(pData, ulDataLen);
+
+       // Verify the data
+       if (!mac->verifyUpdate(data))
+       {
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Get the signature
+       ByteString signature(pSignature, ulSignatureLen);
+
+       // Verify the signature
+       if (!mac->verifyFinal(signature))
+       {
+               session->resetOp();
+               return CKR_SIGNATURE_INVALID;
+       }
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_Verify
+static CK_RV AsymVerify(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       AsymMech::Type mechanism = session->getMechanism();
+       PublicKey* publicKey = session->getPublicKey();
+       size_t paramLen;
+       void* param = session->getParameters(paramLen);
+       if (asymCrypto == NULL || !session->getAllowSinglePartOp() || publicKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = publicKey->getOutputLength();
+
+       // Check buffer size
+       if (ulSignatureLen != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_SIGNATURE_LEN_RANGE;
+       }
+
+       // Get the data
+       ByteString data;
+
+       // We must allow input length <= k and therfore need to prepend the data with zeroes.
+       if (mechanism == AsymMech::RSA) {
+               data.wipe(size-ulDataLen);
+       }
+
+       data += ByteString(pData, ulDataLen);
+       ByteString signature(pSignature, ulSignatureLen);
+
+       // Verify the data
+       if (session->getAllowMultiPartOp())
+       {
+               if (!asymCrypto->verifyUpdate(data) ||
+                   !asymCrypto->verifyFinal(signature))
+               {
+                       session->resetOp();
+                       return CKR_SIGNATURE_INVALID;
+               }
+       }
+       else if (!asymCrypto->verify(publicKey,data,signature,mechanism,param,paramLen))
+       {
+               session->resetOp();
+               return CKR_SIGNATURE_INVALID;
+       }
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Perform a single pass verification operation
+CK_RV SoftHSM::C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pSignature == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_VERIFY)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacVerify(session, pData, ulDataLen,
+                                pSignature, ulSignatureLen);
+       else
+               return AsymVerify(session, pData, ulDataLen,
+                                 pSignature, ulSignatureLen);
+}
+
+// MacAlgorithm version of C_VerifyUpdate
+static CK_RV MacVerifyUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Get the part
+       ByteString part(pPart, ulPartLen);
+
+       // Verify the data
+       if (!mac->verifyUpdate(part))
+       {
+               // verifyUpdate can't fail for a logical reason, so we assume total breakdown.
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       session->setAllowSinglePartOp(false);
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_VerifyUpdate
+static CK_RV AsymVerifyUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       if (asymCrypto == NULL || !session->getAllowMultiPartOp())
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Get the part
+       ByteString part(pPart, ulPartLen);
+
+       // Verify the data
+       if (!asymCrypto->verifyUpdate(part))
+       {
+               // verifyUpdate can't fail for a logical reason, so we assume total breakdown.
+               session->resetOp();
+               return CKR_GENERAL_ERROR;
+       }
+
+       session->setAllowSinglePartOp(false);
+       return CKR_OK;
+}
+
+// Update a running verification operation with additional data
+CK_RV SoftHSM::C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_VERIFY)
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacVerifyUpdate(session, pPart, ulPartLen);
+       else
+               return AsymVerifyUpdate(session, pPart, ulPartLen);
+}
+
+// MacAlgorithm version of C_SignFinal
+static CK_RV MacVerifyFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       MacAlgorithm* mac = session->getMacOp();
+       if (mac == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = mac->getMacSize();
+
+       // Check buffer size
+       if (ulSignatureLen != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_SIGNATURE_LEN_RANGE;
+       }
+
+       // Get the signature
+       ByteString signature(pSignature, ulSignatureLen);
+
+       // Verify the data
+       if (!mac->verifyFinal(signature))
+       {
+               session->resetOp();
+               return CKR_SIGNATURE_INVALID;
+       }
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// AsymmetricAlgorithm version of C_VerifyFinal
+static CK_RV AsymVerifyFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp();
+       PublicKey* publicKey = session->getPublicKey();
+       if (asymCrypto == NULL || publicKey == NULL)
+       {
+               session->resetOp();
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       // Size of the signature
+       CK_ULONG size = publicKey->getOutputLength();
+
+       // Check buffer size
+       if (ulSignatureLen != size)
+       {
+               ERROR_MSG("The size of the signature differs from the size of the mechanism");
+               session->resetOp();
+               return CKR_SIGNATURE_LEN_RANGE;
+       }
+
+       // Get the data
+       ByteString signature(pSignature, ulSignatureLen);
+
+       // Verify the data
+       if (!asymCrypto->verifyFinal(signature))
+       {
+               session->resetOp();
+               return CKR_SIGNATURE_INVALID;
+       }
+
+       session->resetOp();
+       return CKR_OK;
+}
+
+// Finalise the verification operation and check the signature
+CK_RV SoftHSM::C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pSignature == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we are doing the correct operation
+       if (session->getOpType() != SESSION_OP_VERIFY || !session->getAllowMultiPartOp())
+               return CKR_OPERATION_NOT_INITIALIZED;
+
+       if (session->getMacOp() != NULL)
+               return MacVerifyFinal(session, pSignature, ulSignatureLen);
+       else
+               return AsymVerifyFinal(session, pSignature, ulSignatureLen);
+}
+
+// Initialise a verification operation the allows recovery of the signed data from the signature
+CK_RV SoftHSM::C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR /*pMechanism*/, CK_OBJECT_HANDLE /*hKey*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if we have another operation
+       if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Perform a single part verification operation and recover the signed data
+CK_RV SoftHSM::C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pSignature*/, CK_ULONG /*ulSignatureLen*/, CK_BYTE_PTR /*pData*/, CK_ULONG_PTR /*pulDataLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Update a running multi-part encryption and digesting operation
+CK_RV SoftHSM::C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG_PTR /*pulEncryptedPartLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Update a running multi-part decryption and digesting operation
+CK_RV SoftHSM::C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pDecryptedPart*/, CK_ULONG_PTR /*pulDecryptedPartLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Update a running multi-part signing and encryption operation
+CK_RV SoftHSM::C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG_PTR /*pulEncryptedPartLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Update a running multi-part decryption and verification operation
+CK_RV SoftHSM::C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG /*ulEncryptedPartLen*/, CK_BYTE_PTR /*pPart*/, CK_ULONG_PTR /*pulPartLen*/)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Generate a secret key or a domain parameter set using the specified mechanism
+CK_RV SoftHSM::C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check the mechanism, only accept DSA and DH parameters
+       // and symmetric ciphers
+       CK_OBJECT_CLASS objClass;
+       CK_KEY_TYPE keyType;
+       switch (pMechanism->mechanism)
+       {
+               case CKM_DSA_PARAMETER_GEN:
+                       objClass = CKO_DOMAIN_PARAMETERS;
+                       keyType = CKK_DSA;
+                       break;
+               case CKM_DH_PKCS_PARAMETER_GEN:
+                       objClass = CKO_DOMAIN_PARAMETERS;
+                       keyType = CKK_DH;
+                       break;
+#ifndef WITH_FIPS
+               case CKM_DES_KEY_GEN:
+                       objClass = CKO_SECRET_KEY;
+                       keyType = CKK_DES;
+                       break;
+#endif
+               case CKM_DES2_KEY_GEN:
+                       objClass = CKO_SECRET_KEY;
+                       keyType = CKK_DES2;
+                       break;
+               case CKM_DES3_KEY_GEN:
+                       objClass = CKO_SECRET_KEY;
+                       keyType = CKK_DES3;
+                       break;
+               case CKM_AES_KEY_GEN:
+                       objClass = CKO_SECRET_KEY;
+                       keyType = CKK_AES;
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Extract information from the template that is needed to create the object.
+       CK_BBOOL isOnToken = CK_FALSE;
+       CK_BBOOL isPrivate = CK_TRUE;
+       CK_CERTIFICATE_TYPE dummy;
+       bool isImplicit = true;
+       extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit);
+
+       // Report errors and/or unexpected usage.
+       if (objClass != CKO_SECRET_KEY && objClass != CKO_DOMAIN_PARAMETERS)
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       if (pMechanism->mechanism == CKM_DSA_PARAMETER_GEN &&
+           (objClass != CKO_DOMAIN_PARAMETERS || keyType != CKK_DSA))
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DH_PKCS_PARAMETER_GEN &&
+           (objClass != CKO_DOMAIN_PARAMETERS || keyType != CKK_DH))
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DES_KEY_GEN &&
+           (objClass != CKO_SECRET_KEY || keyType != CKK_DES))
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DES2_KEY_GEN &&
+           (objClass != CKO_SECRET_KEY || keyType != CKK_DES2))
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DES3_KEY_GEN &&
+           (objClass != CKO_SECRET_KEY || keyType != CKK_DES3))
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_AES_KEY_GEN &&
+           (objClass != CKO_SECRET_KEY || keyType != CKK_AES))
+               return CKR_TEMPLATE_INCONSISTENT;
+
+       // Check authorization
+       CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Generate DSA domain parameters
+       if (pMechanism->mechanism == CKM_DSA_PARAMETER_GEN)
+       {
+               return this->generateDSAParameters(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       // Generate DH domain parameters
+       if (pMechanism->mechanism == CKM_DH_PKCS_PARAMETER_GEN)
+       {
+               return this->generateDHParameters(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       // Generate DES secret key
+       if (pMechanism->mechanism == CKM_DES_KEY_GEN)
+       {
+               return this->generateDES(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       // Generate DES2 secret key
+       if (pMechanism->mechanism == CKM_DES2_KEY_GEN)
+       {
+               return this->generateDES2(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       // Generate DES3 secret key
+       if (pMechanism->mechanism == CKM_DES3_KEY_GEN)
+       {
+               return this->generateDES3(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       // Generate AES secret key
+       if (pMechanism->mechanism == CKM_AES_KEY_GEN)
+       {
+               return this->generateAES(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate);
+       }
+
+       return CKR_GENERAL_ERROR;
+}
+
+// Generate a key-pair using the specified mechanism
+CK_RV SoftHSM::C_GenerateKeyPair
+(
+       CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey
+)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phPublicKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phPrivateKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check the mechanism, only accept RSA, DSA, EC and DH key pair generation.
+       CK_KEY_TYPE keyType;
+       switch (pMechanism->mechanism)
+       {
+               case CKM_RSA_PKCS_KEY_PAIR_GEN:
+                       keyType = CKK_RSA;
+                       break;
+               case CKM_DSA_KEY_PAIR_GEN:
+                       keyType = CKK_DSA;
+                       break;
+               case CKM_DH_PKCS_KEY_PAIR_GEN:
+                       keyType = CKK_DH;
+                       break;
+#ifdef WITH_ECC
+               case CKM_EC_KEY_PAIR_GEN:
+                       keyType = CKK_EC;
+                       break;
+#endif
+#ifdef WITH_GOST
+               case CKM_GOSTR3410_KEY_PAIR_GEN:
+                       keyType = CKK_GOSTR3410;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       CK_CERTIFICATE_TYPE dummy;
+
+       // Extract information from the public key template that is needed to create the object.
+       CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+       CK_BBOOL ispublicKeyToken = CK_FALSE;
+       CK_BBOOL ispublicKeyPrivate = CK_FALSE;
+       bool isPublicKeyImplicit = true;
+       extractObjectInformation(pPublicKeyTemplate, ulPublicKeyAttributeCount, publicKeyClass, keyType, dummy, ispublicKeyToken, ispublicKeyPrivate, isPublicKeyImplicit);
+
+       // Report errors caused by accidental template mix-ups in the application using this cryptoki lib.
+       if (publicKeyClass != CKO_PUBLIC_KEY)
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN && keyType != CKK_RSA)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN && keyType != CKK_DSA)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN && keyType != CKK_EC)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN && keyType != CKK_DH)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410)
+               return CKR_TEMPLATE_INCONSISTENT;
+
+       // Extract information from the private key template that is needed to create the object.
+       CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+       CK_BBOOL isprivateKeyToken = CK_FALSE;
+       CK_BBOOL isprivateKeyPrivate = CK_TRUE;
+       bool isPrivateKeyImplicit = true;
+       extractObjectInformation(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, privateKeyClass, keyType, dummy, isprivateKeyToken, isprivateKeyPrivate, isPrivateKeyImplicit);
+
+       // Report errors caused by accidental template mix-ups in the application using this cryptoki lib.
+       if (privateKeyClass != CKO_PRIVATE_KEY)
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN && keyType != CKK_RSA)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN && keyType != CKK_DSA)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN && keyType != CKK_EC)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN && keyType != CKK_DH)
+               return CKR_TEMPLATE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410)
+               return CKR_TEMPLATE_INCONSISTENT;
+
+       // Check user credentials
+       CK_RV rv = haveWrite(session->getState(), ispublicKeyToken || isprivateKeyToken, ispublicKeyPrivate || isprivateKeyPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Generate RSA keys
+       if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN)
+       {
+                       return this->generateRSA(hSession,
+                                                                        pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                                                        pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                                                        phPublicKey, phPrivateKey,
+                                                                        ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate);
+       }
+
+       // Generate DSA keys
+       if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN)
+       {
+                       return this->generateDSA(hSession,
+                                                                        pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                                                        pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                                                        phPublicKey, phPrivateKey,
+                                                                        ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate);
+       }
+
+       // Generate EC keys
+       if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN)
+       {
+                       return this->generateEC(hSession,
+                                                                        pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                                                        pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                                                        phPublicKey, phPrivateKey,
+                                                                        ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate);
+       }
+
+       // Generate DH keys
+       if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN)
+       {
+                       return this->generateDH(hSession,
+                                                                        pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                                                        pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                                                        phPublicKey, phPrivateKey,
+                                                                        ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate);
+       }
+
+       // Generate GOST keys
+       if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN)
+       {
+                       return this->generateGOST(hSession,
+                                                                        pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                                                        pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                                                        phPublicKey, phPrivateKey,
+                                                                        ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate);
+       }
+
+       return CKR_GENERAL_ERROR;
+}
+
+// Internal: Wrap blob using symmetric key
+CK_RV SoftHSM::WrapKeySym
+(
+       CK_MECHANISM_PTR pMechanism,
+       Token* token,
+       OSObject* wrapKey,
+       ByteString& keydata,
+       ByteString& wrapped
+)
+{
+       // Get the symmetric algorithm matching the mechanism
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       SymWrap::Type mode = SymWrap::Unknown;
+       size_t bb = 8;
+#ifdef HAVE_AES_KEY_WRAP
+       CK_ULONG wrappedlen = keydata.size();
+
+       // [PKCS#11 v2.40, 2.14.3 AES Key Wrap]
+       // A key whose length is not a multiple of the AES Key Wrap block
+       // size (8 bytes) will be zero padded to fit.
+       CK_ULONG alignment = wrappedlen % 8;
+       if (alignment != 0)
+       {
+               keydata.resize(wrappedlen + 8 - alignment);
+               memset(&keydata[wrappedlen], 0, 8 - alignment);
+               wrappedlen = keydata.size();
+       }
+#endif
+       switch(pMechanism->mechanism) {
+#ifdef HAVE_AES_KEY_WRAP
+               case CKM_AES_KEY_WRAP:
+                       if ((wrappedlen < 16) || ((wrappedlen % 8) != 0))
+                               return CKR_KEY_SIZE_RANGE;
+                       algo = SymAlgo::AES;
+                       mode = SymWrap::AES_KEYWRAP;
+                       break;
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               case CKM_AES_KEY_WRAP_PAD:
+                       algo = SymAlgo::AES;
+                       mode = SymWrap::AES_KEYWRAP_PAD;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* wrappingkey = new SymmetricKey();
+
+       if (getSymmetricKey(wrappingkey, token, wrapKey) != CKR_OK)
+       {
+               cipher->recycleKey(wrappingkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // adjust key bit length
+       wrappingkey->setBitLen(wrappingkey->getKeyBits().size() * bb);
+
+       // Wrap the key
+       if (!cipher->wrapKey(wrappingkey, mode, keydata, wrapped))
+       {
+               cipher->recycleKey(wrappingkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       cipher->recycleKey(wrappingkey);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+       return CKR_OK;
+}
+
+// Internal: Wrap blob using asymmetric key
+CK_RV SoftHSM::WrapKeyAsym
+(
+       CK_MECHANISM_PTR pMechanism,
+       Token* token,
+       OSObject* wrapKey,
+       ByteString& keydata,
+       ByteString& wrapped
+)
+{
+       const size_t bb = 8;
+       AsymAlgo::Type algo = AsymAlgo::Unknown;
+       AsymMech::Type mech = AsymMech::Unknown;
+
+       CK_ULONG modulus_length;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+               case CKM_RSA_PKCS_OAEP:
+                       algo = AsymAlgo::RSA;
+                       if (!wrapKey->attributeExists(CKA_MODULUS_BITS))
+                               return CKR_GENERAL_ERROR;
+                       modulus_length = wrapKey->getUnsignedLongValue(CKA_MODULUS_BITS, 0);
+                       // adjust key bit length
+                       modulus_length /= bb;
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       mech = AsymMech::RSA_PKCS;
+                       // RFC 3447 section 7.2.1
+                       if (keydata.size() > modulus_length - 11)
+                               return CKR_KEY_SIZE_RANGE;
+                       break;
+
+               case CKM_RSA_PKCS_OAEP:
+                       mech = AsymMech::RSA_PKCS_OAEP;
+                       // SHA-1 is the only supported option
+                       // PKCS#11 2.40 draft 2 section 2.1.8: input length <= k-2-2hashLen
+                       if (keydata.size() > modulus_length - 2 - 2 * 160 / 8)
+                               return CKR_KEY_SIZE_RANGE;
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       AsymmetricAlgorithm* cipher = CryptoFactory::i()->getAsymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       PublicKey* publicKey = cipher->newPublicKey();
+       if (publicKey == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+               return CKR_HOST_MEMORY;
+       }
+
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+               case CKM_RSA_PKCS_OAEP:
+                       if (getRSAPublicKey((RSAPublicKey*)publicKey, token, wrapKey) != CKR_OK)
+                       {
+                               cipher->recyclePublicKey(publicKey);
+                               CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+                               return CKR_GENERAL_ERROR;
+                       }
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       // Wrap the key
+       if (!cipher->wrapKey(publicKey, keydata, wrapped, mech))
+       {
+               cipher->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       cipher->recyclePublicKey(publicKey);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+
+       return CKR_OK;
+}
+
+
+// Wrap the specified key using the specified wrapping key and mechanism
+CK_RV SoftHSM::C_WrapKey
+(
+       CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hWrappingKey,
+       CK_OBJECT_HANDLE hKey,
+       CK_BYTE_PTR pWrappedKey,
+       CK_ULONG_PTR pulWrappedKeyLen
+)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pulWrappedKeyLen == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       CK_RV rv;
+       // Check the mechanism, only accept advanced AES key wrapping and RSA
+       switch(pMechanism->mechanism)
+       {
+#ifdef HAVE_AES_KEY_WRAP
+               case CKM_AES_KEY_WRAP:
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               case CKM_AES_KEY_WRAP_PAD:
+#endif
+               case CKM_RSA_PKCS:
+                       // Does not handle optional init vector
+                       if (pMechanism->pParameter != NULL_PTR ||
+                            pMechanism->ulParameterLen != 0)
+                               return CKR_ARGUMENTS_BAD;
+                       break;
+               case CKM_RSA_PKCS_OAEP:
+                       rv = MechParamCheckRSAPKCSOAEP(pMechanism);
+                       if (rv != CKR_OK)
+                               return rv;
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the wrapping key handle.
+       OSObject *wrapKey = (OSObject *)handleManager->getObject(hWrappingKey);
+       if (wrapKey == NULL_PTR || !wrapKey->isValid()) return CKR_WRAPPING_KEY_HANDLE_INVALID;
+
+       CK_BBOOL isWrapKeyOnToken = wrapKey->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isWrapKeyPrivate = wrapKey->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials for the wrapping key
+       rv = haveRead(session->getState(), isWrapKeyOnToken, isWrapKeyPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check wrapping key class and type
+       if ((pMechanism->mechanism == CKM_AES_KEY_WRAP || pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD) && wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY)
+               return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+       if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PUBLIC_KEY)
+               return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_AES_KEY_WRAP && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES)
+               return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES)
+               return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+       if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA)
+               return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+
+       // Check if the wrapping key can be used for wrapping
+       if (wrapKey->getBooleanValue(CKA_WRAP, false) == false)
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+    // Check if the specified mechanism is allowed for the wrapping key
+    if (!isMechanismPermitted(wrapKey, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Check the to be wrapped key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_KEY_HANDLE_INVALID;
+
+       CK_BBOOL isKeyOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials for the to be wrapped key
+       rv = haveRead(session->getState(), isKeyOnToken, isKeyPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if the to be wrapped key can be wrapped
+       if (key->getBooleanValue(CKA_EXTRACTABLE, false) == false)
+               return CKR_KEY_UNEXTRACTABLE;
+       if (key->getBooleanValue(CKA_WRAP_WITH_TRUSTED, false) && wrapKey->getBooleanValue(CKA_TRUSTED, false) == false)
+               return CKR_KEY_NOT_WRAPPABLE;
+
+       // Check the class
+       CK_OBJECT_CLASS keyClass = key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED);
+       if (keyClass != CKO_SECRET_KEY && keyClass != CKO_PRIVATE_KEY)
+               return CKR_KEY_NOT_WRAPPABLE;
+       // CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP can be used only on SECRET keys: PKCS#11 2.40 draft 2 section 2.1.6 PKCS #1 v1.5 RSA & section 2.1.8 PKCS #1 RSA OAEP
+       if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && keyClass != CKO_SECRET_KEY)
+               return CKR_KEY_NOT_WRAPPABLE;
+
+       // Verify the wrap template attribute
+       if (wrapKey->attributeExists(CKA_WRAP_TEMPLATE))
+       {
+               OSAttribute attr = wrapKey->getAttribute(CKA_WRAP_TEMPLATE);
+
+               if (attr.isAttributeMapAttribute())
+               {
+                       typedef std::map<CK_ATTRIBUTE_TYPE,OSAttribute> attrmap_type;
+
+                       const attrmap_type& map = attr.getAttributeMapValue();
+
+                       for (attrmap_type::const_iterator it = map.begin(); it != map.end(); ++it)
+                       {
+                               if (!key->attributeExists(it->first))
+                               {
+                                       return CKR_KEY_NOT_WRAPPABLE;
+                               }
+
+                               OSAttribute keyAttr = key->getAttribute(it->first);
+                               ByteString v1, v2;
+                               if (!keyAttr.peekValue(v1) || !it->second.peekValue(v2) || (v1 != v2))
+                               {
+                                       return CKR_KEY_NOT_WRAPPABLE;
+                               }
+                       }
+               }
+       }
+
+       // Get the key data to encrypt
+       ByteString keydata;
+       if (keyClass == CKO_SECRET_KEY)
+       {
+               if (isKeyPrivate)
+               {
+                       bool bOK = token->decrypt(key->getByteStringValue(CKA_VALUE), keydata);
+                       if (!bOK) return CKR_GENERAL_ERROR;
+               }
+               else
+               {
+                       keydata = key->getByteStringValue(CKA_VALUE);
+               }
+       }
+       else
+       {
+               CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED);
+               AsymAlgo::Type alg = AsymAlgo::Unknown;
+               switch (keyType) {
+                       case CKK_RSA:
+                               alg = AsymAlgo::RSA;
+                               break;
+                       case CKK_DSA:
+                               alg = AsymAlgo::DSA;
+                               break;
+                       case CKK_DH:
+                               alg = AsymAlgo::DH;
+                               break;
+#ifdef WITH_ECC
+                       case CKK_EC:
+                               // can be ecdh too but it doesn't matter
+                               alg = AsymAlgo::ECDSA;
+                               break;
+#endif
+                       default:
+                               return CKR_KEY_NOT_WRAPPABLE;
+               }
+               AsymmetricAlgorithm* asymCrypto = NULL;
+               PrivateKey* privateKey = NULL;
+               asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(alg);
+               if (asymCrypto == NULL)
+                       return CKR_GENERAL_ERROR;
+               privateKey = asymCrypto->newPrivateKey();
+               if (privateKey == NULL)
+               {
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_HOST_MEMORY;
+               }
+               switch (keyType) {
+                       case CKK_RSA:
+                               rv = getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key);
+                               break;
+                       case CKK_DSA:
+                               rv = getDSAPrivateKey((DSAPrivateKey*)privateKey, token, key);
+                               break;
+                       case CKK_DH:
+                               rv = getDHPrivateKey((DHPrivateKey*)privateKey, token, key);
+                               break;
+#ifdef WITH_ECC
+                       case CKK_EC:
+                               rv = getECPrivateKey((ECPrivateKey*)privateKey, token, key);
+                               break;
+#endif
+               }
+               if (rv != CKR_OK)
+               {
+                       asymCrypto->recyclePrivateKey(privateKey);
+                       CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+                       return CKR_GENERAL_ERROR;
+               }
+               keydata = privateKey->PKCS8Encode();
+               asymCrypto->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto);
+       }
+       if (keydata.size() == 0)
+               return CKR_KEY_NOT_WRAPPABLE;
+
+       keyClass = wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED);
+       ByteString wrapped;
+       if (keyClass == CKO_SECRET_KEY)
+               rv = SoftHSM::WrapKeySym(pMechanism, token, wrapKey, keydata, wrapped);
+       else
+               rv = SoftHSM::WrapKeyAsym(pMechanism, token, wrapKey, keydata, wrapped);
+       if (rv != CKR_OK)
+               return rv;
+
+       if (pWrappedKey != NULL) {
+               if (*pulWrappedKeyLen >= wrapped.size())
+                       memcpy(pWrappedKey, wrapped.byte_str(), wrapped.size());
+               else
+                       rv = CKR_BUFFER_TOO_SMALL;
+       }
+
+       *pulWrappedKeyLen = wrapped.size();
+       return rv;
+}
+
+// Internal: Unwrap blob using symmetric key
+CK_RV SoftHSM::UnwrapKeySym
+(
+       CK_MECHANISM_PTR pMechanism,
+       ByteString& wrapped,
+       Token* token,
+       OSObject* unwrapKey,
+       ByteString& keydata
+)
+{
+       // Get the symmetric algorithm matching the mechanism
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       SymWrap::Type mode = SymWrap::Unknown;
+       size_t bb = 8;
+       switch(pMechanism->mechanism) {
+#ifdef HAVE_AES_KEY_WRAP
+               case CKM_AES_KEY_WRAP:
+                       algo = SymAlgo::AES;
+                       mode = SymWrap::AES_KEYWRAP;
+                       break;
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               case CKM_AES_KEY_WRAP_PAD:
+                       algo = SymAlgo::AES;
+                       mode = SymWrap::AES_KEYWRAP_PAD;
+                       break;
+#endif
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* unwrappingkey = new SymmetricKey();
+
+       if (getSymmetricKey(unwrappingkey, token, unwrapKey) != CKR_OK)
+       {
+               cipher->recycleKey(unwrappingkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // adjust key bit length
+       unwrappingkey->setBitLen(unwrappingkey->getKeyBits().size() * bb);
+
+       // Unwrap the key
+       CK_RV rv = CKR_OK;
+       if (!cipher->unwrapKey(unwrappingkey, mode, wrapped, keydata))
+               rv = CKR_GENERAL_ERROR;
+       cipher->recycleKey(unwrappingkey);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+       return rv;
+}
+
+// Internal: Unwrap blob using asymmetric key
+CK_RV SoftHSM::UnwrapKeyAsym
+(
+       CK_MECHANISM_PTR pMechanism,
+       ByteString& wrapped,
+       Token* token,
+       OSObject* unwrapKey,
+       ByteString& keydata
+)
+{
+       // Get the symmetric algorithm matching the mechanism
+       AsymAlgo::Type algo = AsymAlgo::Unknown;
+       AsymMech::Type mode = AsymMech::Unknown;
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+                       algo = AsymAlgo::RSA;
+                       mode = AsymMech::RSA_PKCS;
+                       break;
+
+               case CKM_RSA_PKCS_OAEP:
+                       algo = AsymAlgo::RSA;
+                       mode = AsymMech::RSA_PKCS_OAEP;
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+       AsymmetricAlgorithm* cipher = CryptoFactory::i()->getAsymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       PrivateKey* unwrappingkey = cipher->newPrivateKey();
+       if (unwrappingkey == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+               return CKR_HOST_MEMORY;
+       }
+
+       switch(pMechanism->mechanism) {
+               case CKM_RSA_PKCS:
+               case CKM_RSA_PKCS_OAEP:
+                       if (getRSAPrivateKey((RSAPrivateKey*)unwrappingkey, token, unwrapKey) != CKR_OK)
+                       {
+                               cipher->recyclePrivateKey(unwrappingkey);
+                               CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+                               return CKR_GENERAL_ERROR;
+                       }
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Unwrap the key
+       CK_RV rv = CKR_OK;
+       if (!cipher->unwrapKey(unwrappingkey, wrapped, keydata, mode))
+               rv = CKR_GENERAL_ERROR;
+       cipher->recyclePrivateKey(unwrappingkey);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher);
+       return rv;
+}
+
+// Unwrap the specified key using the specified unwrapping key
+CK_RV SoftHSM::C_UnwrapKey
+(
+       CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hUnwrappingKey,
+       CK_BYTE_PTR pWrappedKey,
+       CK_ULONG ulWrappedKeyLen,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR hKey
+)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pWrappedKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (hKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       CK_RV rv;
+       // Check the mechanism
+       switch(pMechanism->mechanism)
+       {
+#ifdef HAVE_AES_KEY_WRAP
+               case CKM_AES_KEY_WRAP:
+                       if ((ulWrappedKeyLen < 24) || ((ulWrappedKeyLen % 8) != 0))
+                               return CKR_WRAPPED_KEY_LEN_RANGE;
+                       // Does not handle optional init vector
+                       if (pMechanism->pParameter != NULL_PTR ||
+                            pMechanism->ulParameterLen != 0)
+                               return CKR_ARGUMENTS_BAD;
+                       break;
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+               case CKM_AES_KEY_WRAP_PAD:
+                       if ((ulWrappedKeyLen < 16) || ((ulWrappedKeyLen % 8) != 0))
+                               return CKR_WRAPPED_KEY_LEN_RANGE;
+                       // Does not handle optional init vector
+                       if (pMechanism->pParameter != NULL_PTR ||
+                            pMechanism->ulParameterLen != 0)
+                               return CKR_ARGUMENTS_BAD;
+                       break;
+#endif
+               case CKM_RSA_PKCS:
+                       // Input length checks needs to be done later when unwrapping key is known
+                       break;
+               case CKM_RSA_PKCS_OAEP:
+                       rv = MechParamCheckRSAPKCSOAEP(pMechanism);
+                       if (rv != CKR_OK)
+                               return rv;
+                       break;
+
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the unwrapping key handle.
+       OSObject *unwrapKey = (OSObject *)handleManager->getObject(hUnwrappingKey);
+       if (unwrapKey == NULL_PTR || !unwrapKey->isValid()) return CKR_UNWRAPPING_KEY_HANDLE_INVALID;
+
+       CK_BBOOL isUnwrapKeyOnToken = unwrapKey->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isUnwrapKeyPrivate = unwrapKey->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials
+       rv = haveRead(session->getState(), isUnwrapKeyOnToken, isUnwrapKeyPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check unwrapping key class and type
+       if ((pMechanism->mechanism == CKM_AES_KEY_WRAP || pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD) && unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY)
+               return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_AES_KEY_WRAP && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES)
+               return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+       if (pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES)
+               return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+       if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY)
+               return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+       if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA)
+               return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+
+       // Check if the unwrapping key can be used for unwrapping
+       if (unwrapKey->getBooleanValue(CKA_UNWRAP, false) == false)
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the unwrap key
+       if (!isMechanismPermitted(unwrapKey, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Extract information from the template that is needed to create the object.
+       CK_OBJECT_CLASS objClass;
+       CK_KEY_TYPE keyType;
+       CK_BBOOL isOnToken = CK_FALSE;
+       CK_BBOOL isPrivate = CK_TRUE;
+       CK_CERTIFICATE_TYPE dummy;
+       bool isImplicit = false;
+       rv = extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit);
+       if (rv != CKR_OK)
+       {
+               ERROR_MSG("Mandatory attribute not present in template");
+               return rv;
+       }
+
+       // Report errors and/or unexpected usage.
+       if (objClass != CKO_SECRET_KEY && objClass != CKO_PRIVATE_KEY)
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       // Key type will be handled at object creation
+
+       // Check authorization
+       rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Build unwrapped key template
+       const CK_ULONG maxAttribs = 32;
+       CK_ATTRIBUTE secretAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) }
+       };
+       CK_ULONG secretAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - secretAttribsCount))
+               return CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i = 0; i < ulCount; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                               continue;
+                       default:
+                               secretAttribs[secretAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       // Apply the unwrap template
+       if (unwrapKey->attributeExists(CKA_UNWRAP_TEMPLATE))
+       {
+               OSAttribute unwrapAttr = unwrapKey->getAttribute(CKA_UNWRAP_TEMPLATE);
+
+               if (unwrapAttr.isAttributeMapAttribute())
+               {
+                       typedef std::map<CK_ATTRIBUTE_TYPE,OSAttribute> attrmap_type;
+
+                       const attrmap_type& map = unwrapAttr.getAttributeMapValue();
+
+                       for (attrmap_type::const_iterator it = map.begin(); it != map.end(); ++it)
+                       {
+                               CK_ATTRIBUTE* attr = NULL;
+                               for (CK_ULONG i = 0; i < secretAttribsCount; ++i)
+                               {
+                                       if (it->first == secretAttribs[i].type)
+                                       {
+                                               if (attr != NULL)
+                                               {
+                                                       return CKR_TEMPLATE_INCONSISTENT;
+                                               }
+                                               attr = &secretAttribs[i];
+                                               ByteString value;
+                                               it->second.peekValue(value);
+                                               if (attr->ulValueLen != value.size())
+                                               {
+                                                       return CKR_TEMPLATE_INCONSISTENT;
+                                               }
+                                               if (memcmp(attr->pValue, value.const_byte_str(), value.size()) != 0)
+                                               {
+                                                       return CKR_TEMPLATE_INCONSISTENT;
+                                               }
+                                       }
+                               }
+                               if (attr == NULL)
+                               {
+                                       return CKR_TEMPLATE_INCONSISTENT;
+                               }
+                       }
+               }
+       }
+
+       *hKey = CK_INVALID_HANDLE;
+
+       // Unwrap the key
+       ByteString wrapped(pWrappedKey, ulWrappedKeyLen);
+       ByteString keydata;
+       if (unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_SECRET_KEY)
+               rv = UnwrapKeySym(pMechanism, wrapped, token, unwrapKey, keydata);
+       else if (unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_PRIVATE_KEY)
+               rv = UnwrapKeyAsym(pMechanism, wrapped, token, unwrapKey, keydata);
+       else
+               rv = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+       if (rv != CKR_OK)
+               return rv;
+
+       // Create the secret object using C_CreateObject
+       rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, hKey, OBJECT_OP_UNWRAP);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*hKey);
+               if (osobject == NULL_PTR || !osobject->isValid())
+                       rv = CKR_FUNCTION_FAILED;
+               if (osobject->startTransaction())
+               {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL, false);
+
+                       // Common Secret Key Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE, false);
+                       bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, false);
+
+                       // Secret Attributes
+                       if (objClass == CKO_SECRET_KEY)
+                       {
+                               ByteString value;
+                               if (isPrivate)
+                                       token->encrypt(keydata, value);
+                               else
+                                       value = keydata;
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       }
+                       else if (keyType == CKK_RSA)
+                       {
+                               bOK = bOK && setRSAPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE);
+                       }
+                       else if (keyType == CKK_DSA)
+                       {
+                               bOK = bOK && setDSAPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE);
+                       }
+                       else if (keyType == CKK_DH)
+                       {
+                               bOK = bOK && setDHPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE);
+                       }
+                       else if (keyType == CKK_EC)
+                       {
+                               bOK = bOK && setECPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE);
+                       }
+                       else
+                               bOK = false;
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               }
+               else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Remove secret that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*hKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* obj = (OSObject*)handleManager->getObject(*hKey);
+                       handleManager->destroyObject(*hKey);
+                       if (obj) obj->destroyObject();
+                       *hKey = CK_INVALID_HANDLE;
+               }
+
+       }
+
+       return rv;
+}
+
+// Derive a key from the specified base key
+CK_RV SoftHSM::C_DeriveKey
+(
+       CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hBaseKey,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey
+)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phKey == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check the mechanism, only accept DH and ECDH derive
+       switch (pMechanism->mechanism)
+       {
+               case CKM_DH_PKCS_DERIVE:
+#ifdef WITH_ECC
+               case CKM_ECDH1_DERIVE:
+#endif
+#ifndef WITH_FIPS
+               case CKM_DES_ECB_ENCRYPT_DATA:
+               case CKM_DES_CBC_ENCRYPT_DATA:
+#endif
+               case CKM_DES3_ECB_ENCRYPT_DATA:
+               case CKM_DES3_CBC_ENCRYPT_DATA:
+               case CKM_AES_ECB_ENCRYPT_DATA:
+               case CKM_AES_CBC_ENCRYPT_DATA:
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism");
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL) return CKR_GENERAL_ERROR;
+
+       // Check the key handle.
+       OSObject *key = (OSObject *)handleManager->getObject(hBaseKey);
+       if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       CK_BBOOL isKeyOnToken = key->getBooleanValue(CKA_TOKEN, false);
+       CK_BBOOL isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, true);
+
+       // Check user credentials
+       CK_RV rv = haveRead(session->getState(), isKeyOnToken, isKeyPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+
+               return rv;
+       }
+
+       // Check if key can be used for derive
+       if (!key->getBooleanValue(CKA_DERIVE, false))
+               return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+       // Check if the specified mechanism is allowed for the key
+       if (!isMechanismPermitted(key, pMechanism))
+               return CKR_MECHANISM_INVALID;
+
+       // Extract information from the template that is needed to create the object.
+       CK_OBJECT_CLASS objClass;
+       CK_KEY_TYPE keyType;
+       CK_BBOOL isOnToken = CK_FALSE;
+       CK_BBOOL isPrivate = CK_TRUE;
+       CK_CERTIFICATE_TYPE dummy;
+       bool isImplicit = false;
+       rv = extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit);
+       if (rv != CKR_OK)
+       {
+               ERROR_MSG("Mandatory attribute not present in template");
+               return rv;
+       }
+
+       // Report errors and/or unexpected usage.
+       if (objClass != CKO_SECRET_KEY)
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       if (keyType != CKK_GENERIC_SECRET &&
+           keyType != CKK_DES &&
+           keyType != CKK_DES2 &&
+           keyType != CKK_DES3 &&
+           keyType != CKK_AES)
+               return CKR_TEMPLATE_INCONSISTENT;
+
+       // Check authorization
+       rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Derive DH secret
+       if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE)
+       {
+               // Check key class and type
+               if (key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DH)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+
+               return this->deriveDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate);
+       }
+
+#ifdef WITH_ECC
+       // Derive ECDH secret
+       if (pMechanism->mechanism == CKM_ECDH1_DERIVE)
+       {
+               // Check key class and type
+               if (key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_EC)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+
+               return this->deriveECDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate);
+       }
+#endif
+
+       // Derive symmetric secret
+       if (pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA)
+       {
+               // Check key class and type
+               CK_KEY_TYPE baseKeyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED);
+               if (key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA &&
+                   baseKeyType != CKK_DES)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA &&
+                   baseKeyType != CKK_DES)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA &&
+                   baseKeyType != CKK_DES2 && baseKeyType != CKK_DES3)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA &&
+                   baseKeyType != CKK_DES2 && baseKeyType != CKK_DES3)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA &&
+                   baseKeyType != CKK_AES)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+               if (pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA &&
+                   baseKeyType != CKK_AES)
+                       return CKR_KEY_TYPE_INCONSISTENT;
+
+               return this->deriveSymmetric(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate);
+       }
+
+       return CKR_MECHANISM_INVALID;
+}
+
+// Seed the random number generator with new data
+CK_RV SoftHSM::C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pSeed == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the RNG
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL) return CKR_GENERAL_ERROR;
+
+       // Seed the RNG
+       ByteString seed(pSeed, ulSeedLen);
+       rng->seed(seed);
+
+       return CKR_OK;
+}
+
+// Generate the specified amount of random data
+CK_RV SoftHSM::C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pRandomData == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the RNG
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL) return CKR_GENERAL_ERROR;
+
+       // Generate random data
+       ByteString randomData;
+       if (!rng->generateRandom(randomData, ulRandomLen)) return CKR_GENERAL_ERROR;
+
+       // Return random data
+       if (ulRandomLen != 0)
+       {
+               memcpy(pRandomData, randomData.byte_str(), ulRandomLen);
+       }
+
+       return CKR_OK;
+}
+
+// Legacy function
+CK_RV SoftHSM::C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+// Legacy function
+CK_RV SoftHSM::C_CancelFunction(CK_SESSION_HANDLE hSession)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+// Wait or poll for a slot event on the specified slot
+CK_RV SoftHSM::C_WaitForSlotEvent(CK_FLAGS /*flags*/, CK_SLOT_ID_PTR /*pSlot*/, CK_VOID_PTR /*pReserved*/)
+{
+       return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+// Generate an AES secret key
+CK_RV SoftHSM::generateAES
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t keyLen = 0;
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_VALUE_LEN:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               keyLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // CKA_VALUE_LEN must be specified
+       if (keyLen == 0)
+       {
+               INFO_MSG("Missing CKA_VALUE_LEN in pTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // keyLen must be 16, 24, or 32
+       if (keyLen != 16 && keyLen != 24 && keyLen != 32)
+       {
+               INFO_MSG("bad AES key length");
+               return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Generate the secret key
+       AESKey* key = new AESKey(keyLen * 8);
+       SymmetricAlgorithm* aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
+       if (aes == NULL)
+       {
+               ERROR_MSG("Could not get SymmetricAlgorithm");
+               delete key;
+               return CKR_GENERAL_ERROR;
+       }
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL)
+       {
+               ERROR_MSG("Could not get RNG");
+               aes->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
+               return CKR_GENERAL_ERROR;
+       }
+       if (!aes->generateKey(*key, rng))
+       {
+               ERROR_MSG("Could not generate AES secret key");
+               aes->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
+               return CKR_GENERAL_ERROR;
+       }
+
+       CK_RV rv = CKR_OK;
+
+       // Create the secret key object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_AES;
+       CK_ATTRIBUTE keyAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG keyAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - keyAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       keyAttribs[keyAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, keyAttribs, keyAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_AES_KEY_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // Common Secret Key Attributes
+                       bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                       bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                       bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                       // AES Secret Key Attributes
+                       ByteString value;
+                       ByteString kcv;
+                       if (isPrivate)
+                       {
+                               token->encrypt(key->getKeyBits(), value);
+                               token->encrypt(key->getKeyCheckValue(), kcv);
+                       }
+                       else
+                       {
+                               value = key->getKeyBits();
+                               kcv = key->getKeyCheckValue();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       aes->recycleKey(key);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
+
+       // Remove the key that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* oskey = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (oskey) oskey->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DES secret key
+CK_RV SoftHSM::generateDES
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Generate the secret key
+       DESKey* key = new DESKey(56);
+       SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES);
+       if (des == NULL)
+       {
+               ERROR_MSG("Could not get SymmetricAlgorithm");
+               delete key;
+               return CKR_GENERAL_ERROR;
+       }
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL)
+       {
+               ERROR_MSG("Could not get RNG");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+       if (!des->generateKey(*key, rng))
+       {
+               ERROR_MSG("Could not generate DES secret key");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+
+       CK_RV rv = CKR_OK;
+
+       // Create the secret key object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_DES;
+       CK_ATTRIBUTE keyAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG keyAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - keyAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       keyAttribs[keyAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, keyAttribs, keyAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DES_KEY_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // Common Secret Key Attributes
+                       bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                       bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                       bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                       // DES Secret Key Attributes
+                       ByteString value;
+                       ByteString kcv;
+                       if (isPrivate)
+                       {
+                               token->encrypt(key->getKeyBits(), value);
+                               token->encrypt(key->getKeyCheckValue(), kcv);
+                       }
+                       else
+                       {
+                               value = key->getKeyBits();
+                               kcv = key->getKeyCheckValue();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       des->recycleKey(key);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+
+       // Remove the key that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* oskey = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (oskey) oskey->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DES2 secret key
+CK_RV SoftHSM::generateDES2
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Generate the secret key
+       DESKey* key = new DESKey(112);
+       SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES3);
+       if (des == NULL)
+       {
+               ERROR_MSG("Could not get SymmetricAlgorith");
+               delete key;
+               return CKR_GENERAL_ERROR;
+       }
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL)
+       {
+               ERROR_MSG("Could not get RNG");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+       if (!des->generateKey(*key, rng))
+       {
+               ERROR_MSG("Could not generate DES secret key");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+
+       CK_RV rv = CKR_OK;
+
+       // Create the secret key object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_DES2;
+       CK_ATTRIBUTE keyAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG keyAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - keyAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       keyAttribs[keyAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, keyAttribs, keyAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DES2_KEY_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // Common Secret Key Attributes
+                       bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                       bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                       bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                       // DES Secret Key Attributes
+                       ByteString value;
+                       ByteString kcv;
+                       if (isPrivate)
+                       {
+                               token->encrypt(key->getKeyBits(), value);
+                               token->encrypt(key->getKeyCheckValue(), kcv);
+                       }
+                       else
+                       {
+                               value = key->getKeyBits();
+                               kcv = key->getKeyCheckValue();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       des->recycleKey(key);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+
+       // Remove the key that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* oskey = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (oskey) oskey->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DES3 secret key
+CK_RV SoftHSM::generateDES3
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Generate the secret key
+       DESKey* key = new DESKey(168);
+       SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES3);
+       if (des == NULL)
+       {
+               ERROR_MSG("Could not get SymmetricAlgorithm");
+               delete key;
+               return CKR_GENERAL_ERROR;
+       }
+       RNG* rng = CryptoFactory::i()->getRNG();
+       if (rng == NULL)
+       {
+               ERROR_MSG("Could not get RNG");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+       if (!des->generateKey(*key, rng))
+       {
+               ERROR_MSG("Could not generate DES secret key");
+               des->recycleKey(key);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+               return CKR_GENERAL_ERROR;
+       }
+
+       CK_RV rv = CKR_OK;
+
+       // Create the secret key object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_DES3;
+       CK_ATTRIBUTE keyAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG keyAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - keyAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       keyAttribs[keyAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, keyAttribs, keyAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DES3_KEY_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // Common Secret Key Attributes
+                       bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                       bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                       bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                       // DES Secret Key Attributes
+                       ByteString value;
+                       ByteString kcv;
+                       if (isPrivate)
+                       {
+                               token->encrypt(key->getKeyBits(), value);
+                               token->encrypt(key->getKeyCheckValue(), kcv);
+                       }
+                       else
+                       {
+                               value = key->getKeyBits();
+                               kcv = key->getKeyCheckValue();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       des->recycleKey(key);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+
+       // Remove the key that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* oskey = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (oskey) oskey->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate an RSA key pair
+CK_RV SoftHSM::generateRSA
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey,
+       CK_BBOOL isPublicKeyOnToken,
+       CK_BBOOL isPublicKeyPrivate,
+       CK_BBOOL isPrivateKeyOnToken,
+       CK_BBOOL isPrivateKeyPrivate
+)
+{
+       *phPublicKey = CK_INVALID_HANDLE;
+       *phPrivateKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired key information: bitlen and public exponent
+       size_t bitLen = 0;
+       ByteString exponent("010001");
+       for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++)
+       {
+               switch (pPublicKeyTemplate[i].type)
+               {
+                       case CKA_MODULUS_BITS:
+                               if (pPublicKeyTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_MODULUS_BITS does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               bitLen = *(CK_ULONG*)pPublicKeyTemplate[i].pValue;
+                               break;
+                       case CKA_PUBLIC_EXPONENT:
+                               exponent = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // CKA_MODULUS_BITS must be specified to be able to generate a key pair.
+       if (bitLen == 0) {
+               INFO_MSG("Missing CKA_MODULUS_BITS in pPublicKeyTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Set the parameters
+       RSAParameters p;
+       p.setE(exponent);
+       p.setBitLength(bitLen);
+
+       // Generate key pair
+       AsymmetricKeyPair* kp = NULL;
+       AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+       if (rsa == NULL)
+               return CKR_GENERAL_ERROR;
+       if (!rsa->generateKeyPair(&kp, &p))
+       {
+               ERROR_MSG("Could not generate key pair");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+               return CKR_GENERAL_ERROR;
+       }
+
+       RSAPublicKey* pub = (RSAPublicKey*) kp->getPublicKey();
+       RSAPrivateKey* priv = (RSAPrivateKey*) kp->getPrivateKey();
+
+       CK_RV rv = CKR_OK;
+
+       // Create a public key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+               CK_KEY_TYPE publicKeyType = CKK_RSA;
+               CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) },
+                       { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) },
+                       { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) },
+                       { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) },
+               };
+               CK_ULONG publicKeyAttribsCount = 4;
+
+               // Add the additional
+               if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPublicKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                               case CKA_PUBLIC_EXPONENT:
+                                       continue;
+                               default:
+                                       publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_RSA_PKCS_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // RSA Public Key Attributes
+                               ByteString modulus;
+                               ByteString publicExponent;
+                               if (isPublicKeyPrivate)
+                               {
+                                       token->encrypt(pub->getN(), modulus);
+                                       token->encrypt(pub->getE(), publicExponent);
+                               }
+                               else
+                               {
+                                       modulus = pub->getN();
+                                       publicExponent = pub->getE();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_MODULUS, modulus);
+                               bOK = bOK && osobject->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Create a private key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+               CK_KEY_TYPE privateKeyType = CKK_RSA;
+               CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) },
+                       { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) },
+                       { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) },
+                       { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) },
+               };
+               CK_ULONG privateKeyAttribsCount = 4;
+               if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPrivateKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_RSA_PKCS_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // Common Private Key Attributes
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                               // RSA Private Key Attributes
+                               ByteString modulus;
+                               ByteString publicExponent;
+                               ByteString privateExponent;
+                               ByteString prime1;
+                               ByteString prime2;
+                               ByteString exponent1;
+                               ByteString exponent2;
+                               ByteString coefficient;
+                               if (isPrivateKeyPrivate)
+                               {
+                                       token->encrypt(priv->getN(), modulus);
+                                       token->encrypt(priv->getE(), publicExponent);
+                                       token->encrypt(priv->getD(), privateExponent);
+                                       token->encrypt(priv->getP(), prime1);
+                                       token->encrypt(priv->getQ(), prime2);
+                                       token->encrypt(priv->getDP1(), exponent1);
+                                       token->encrypt(priv->getDQ1(), exponent2);
+                                       token->encrypt(priv->getPQ(), coefficient);
+                               }
+                               else
+                               {
+                                       modulus = priv->getN();
+                                       publicExponent = priv->getE();
+                                       privateExponent = priv->getD();
+                                       prime1 = priv->getP();
+                                       prime2 = priv->getQ();
+                                       exponent1 =  priv->getDP1();
+                                       exponent2 = priv->getDQ1();
+                                       coefficient = priv->getPQ();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_MODULUS, modulus);
+                               bOK = bOK && osobject->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent);
+                               bOK = bOK && osobject->setAttribute(CKA_PRIVATE_EXPONENT, privateExponent);
+                               bOK = bOK && osobject->setAttribute(CKA_PRIME_1, prime1);
+                               bOK = bOK && osobject->setAttribute(CKA_PRIME_2, prime2);
+                               bOK = bOK && osobject->setAttribute(CKA_EXPONENT_1,exponent1);
+                               bOK = bOK && osobject->setAttribute(CKA_EXPONENT_2, exponent2);
+                               bOK = bOK && osobject->setAttribute(CKA_COEFFICIENT, coefficient);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Clean up
+       rsa->recycleKeyPair(kp);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+
+       // Remove keys that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phPrivateKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       handleManager->destroyObject(*phPrivateKey);
+                       if (ospriv) ospriv->destroyObject();
+                       *phPrivateKey = CK_INVALID_HANDLE;
+               }
+
+               if (*phPublicKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
+                       handleManager->destroyObject(*phPublicKey);
+                       if (ospub) ospub->destroyObject();
+                       *phPublicKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DSA key pair
+CK_RV SoftHSM::generateDSA
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey,
+       CK_BBOOL isPublicKeyOnToken,
+       CK_BBOOL isPublicKeyPrivate,
+       CK_BBOOL isPrivateKeyOnToken,
+       CK_BBOOL isPrivateKeyPrivate)
+{
+       *phPublicKey = CK_INVALID_HANDLE;
+       *phPrivateKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired key information
+       ByteString prime;
+       ByteString subprime;
+       ByteString generator;
+       for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++)
+       {
+               switch (pPublicKeyTemplate[i].type)
+               {
+                       case CKA_PRIME:
+                               prime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       case CKA_SUBPRIME:
+                               subprime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       case CKA_BASE:
+                               generator = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // The parameters must be specified to be able to generate a key pair.
+       if (prime.size() == 0 || subprime.size() == 0 || generator.size() == 0) {
+               INFO_MSG("Missing parameter(s) in pPublicKeyTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Set the parameters
+       DSAParameters p;
+       p.setP(prime);
+       p.setQ(subprime);
+       p.setG(generator);
+
+       // Generate key pair
+       AsymmetricKeyPair* kp = NULL;
+       AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+       if (dsa == NULL) return CKR_GENERAL_ERROR;
+       if (!dsa->generateKeyPair(&kp, &p))
+       {
+               ERROR_MSG("Could not generate key pair");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+               return CKR_GENERAL_ERROR;
+       }
+
+       DSAPublicKey* pub = (DSAPublicKey*) kp->getPublicKey();
+       DSAPrivateKey* priv = (DSAPrivateKey*) kp->getPrivateKey();
+
+       CK_RV rv = CKR_OK;
+
+       // Create a public key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+               CK_KEY_TYPE publicKeyType = CKK_DSA;
+               CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) },
+                       { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) },
+                       { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) },
+                       { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) },
+               };
+               CK_ULONG publicKeyAttribsCount = 4;
+
+               // Add the additional
+               if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPublicKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DSA_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // DSA Public Key Attributes
+                               ByteString value;
+                               if (isPublicKeyPrivate)
+                               {
+                                       token->encrypt(pub->getY(), value);
+                               }
+                               else
+                               {
+                                       value = pub->getY();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Create a private key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+               CK_KEY_TYPE privateKeyType = CKK_DSA;
+               CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) },
+                       { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) },
+                       { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) },
+                       { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) },
+               };
+               CK_ULONG privateKeyAttribsCount = 4;
+               if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPrivateKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DSA_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // Common Private Key Attributes
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                               // DSA Private Key Attributes
+                               ByteString bPrime;
+                               ByteString bSubprime;
+                               ByteString bGenerator;
+                               ByteString bValue;
+                               if (isPrivateKeyPrivate)
+                               {
+                                       token->encrypt(priv->getP(), bPrime);
+                                       token->encrypt(priv->getQ(), bSubprime);
+                                       token->encrypt(priv->getG(), bGenerator);
+                                       token->encrypt(priv->getX(), bValue);
+                               }
+                               else
+                               {
+                                       bPrime = priv->getP();
+                                       bSubprime = priv->getQ();
+                                       bGenerator = priv->getG();
+                                       bValue = priv->getX();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_PRIME, bPrime);
+                               bOK = bOK && osobject->setAttribute(CKA_SUBPRIME, bSubprime);
+                               bOK = bOK && osobject->setAttribute(CKA_BASE, bGenerator);
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, bValue);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Clean up
+       dsa->recycleKeyPair(kp);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+
+       // Remove keys that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phPrivateKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       handleManager->destroyObject(*phPrivateKey);
+                       if (ospriv) ospriv->destroyObject();
+                       *phPrivateKey = CK_INVALID_HANDLE;
+               }
+
+               if (*phPublicKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
+                       handleManager->destroyObject(*phPublicKey);
+                       if (ospub) ospub->destroyObject();
+                       *phPublicKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DSA domain parameter set
+CK_RV SoftHSM::generateDSAParameters
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t bitLen = 0;
+       size_t qLen = 0;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_PRIME_BITS:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_PRIME_BITS does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               bitLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       case CKA_SUBPRIME_BITS:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_SUBPRIME_BITS does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               qLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // CKA_PRIME_BITS must be specified
+       if (bitLen == 0)
+       {
+               INFO_MSG("Missing CKA_PRIME_BITS in pTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // No real choice for CKA_SUBPRIME_BITS
+       if ((qLen != 0) &&
+           (((bitLen >= 2048) && (qLen != 256)) ||
+            ((bitLen < 2048) && (qLen != 160))))
+               INFO_MSG("CKA_SUBPRIME_BITS is ignored");
+
+
+       // Generate domain parameters
+       AsymmetricParameters* p = NULL;
+       AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+       if (dsa == NULL) return CKR_GENERAL_ERROR;
+       if (!dsa->generateParameters(&p, (void *)bitLen))
+       {
+               ERROR_MSG("Could not generate parameters");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+               return CKR_GENERAL_ERROR;
+       }
+
+       DSAParameters* params = (DSAParameters*) p;
+
+       CK_RV rv = CKR_OK;
+
+       // Create the domain parameter object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_DOMAIN_PARAMETERS;
+       CK_KEY_TYPE keyType = CKK_DSA;
+       CK_ATTRIBUTE paramsAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG paramsAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - paramsAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                               continue;
+               default:
+                       paramsAttribs[paramsAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, paramsAttribs, paramsAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DSA_PARAMETER_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // DSA Domain Parameters Attributes
+                       ByteString prime;
+                       ByteString subprime;
+                       ByteString generator;
+                       if (isPrivate)
+                       {
+                               token->encrypt(params->getP(), prime);
+                               token->encrypt(params->getQ(), subprime);
+                               token->encrypt(params->getG(), generator);
+                       }
+                       else
+                       {
+                               prime = params->getP();
+                               subprime = params->getQ();
+                               generator = params->getG();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_PRIME, prime);
+                       bOK = bOK && osobject->setAttribute(CKA_SUBPRIME, subprime);
+                       bOK = bOK && osobject->setAttribute(CKA_BASE, generator);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       dsa->recycleParameters(p);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+
+       // Remove parameters that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* osparams = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (osparams) osparams->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate an EC key pair
+CK_RV SoftHSM::generateEC
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey,
+       CK_BBOOL isPublicKeyOnToken,
+       CK_BBOOL isPublicKeyPrivate,
+       CK_BBOOL isPrivateKeyOnToken,
+       CK_BBOOL isPrivateKeyPrivate)
+{
+       *phPublicKey = CK_INVALID_HANDLE;
+       *phPrivateKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired key information
+       ByteString params;
+       for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++)
+       {
+               switch (pPublicKeyTemplate[i].type)
+               {
+                       case CKA_EC_PARAMS:
+                               params = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // The parameters must be specified to be able to generate a key pair.
+       if (params.size() == 0) {
+               INFO_MSG("Missing parameter(s) in pPublicKeyTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Set the parameters
+       ECParameters p;
+       p.setEC(params);
+
+       // Generate key pair
+       AsymmetricKeyPair* kp = NULL;
+       AsymmetricAlgorithm* ec = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+       if (ec == NULL) return CKR_GENERAL_ERROR;
+       if (!ec->generateKeyPair(&kp, &p))
+       {
+               ERROR_MSG("Could not generate key pair");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ec);
+               return CKR_GENERAL_ERROR;
+       }
+
+       ECPublicKey* pub = (ECPublicKey*) kp->getPublicKey();
+       ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
+
+       CK_RV rv = CKR_OK;
+
+       // Create a public key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+               CK_KEY_TYPE publicKeyType = CKK_EC;
+               CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) },
+                       { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) },
+                       { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) },
+                       { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) },
+               };
+               CK_ULONG publicKeyAttribsCount = 4;
+
+               // Add the additional
+               if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPublicKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // EC Public Key Attributes
+                               ByteString point;
+                               if (isPublicKeyPrivate)
+                               {
+                                       token->encrypt(pub->getQ(), point);
+                               }
+                               else
+                               {
+                                       point = pub->getQ();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_EC_POINT, point);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Create a private key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+               CK_KEY_TYPE privateKeyType = CKK_EC;
+               CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) },
+                       { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) },
+                       { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) },
+                       { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) },
+               };
+               CK_ULONG privateKeyAttribsCount = 4;
+               if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPrivateKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // Common Private Key Attributes
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                               // EC Private Key Attributes
+                               ByteString group;
+                               ByteString value;
+                               if (isPrivateKeyPrivate)
+                               {
+                                       token->encrypt(priv->getEC(), group);
+                                       token->encrypt(priv->getD(), value);
+                               }
+                               else
+                               {
+                                       group = priv->getEC();
+                                       value = priv->getD();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_EC_PARAMS, group);
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Clean up
+       ec->recycleKeyPair(kp);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ec);
+
+       // Remove keys that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phPrivateKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       handleManager->destroyObject(*phPrivateKey);
+                       if (ospriv) ospriv->destroyObject();
+                       *phPrivateKey = CK_INVALID_HANDLE;
+               }
+
+               if (*phPublicKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
+                       handleManager->destroyObject(*phPublicKey);
+                       if (ospub) ospub->destroyObject();
+                       *phPublicKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DH key pair
+CK_RV SoftHSM::generateDH
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey,
+       CK_BBOOL isPublicKeyOnToken,
+       CK_BBOOL isPublicKeyPrivate,
+       CK_BBOOL isPrivateKeyOnToken,
+       CK_BBOOL isPrivateKeyPrivate)
+{
+       *phPublicKey = CK_INVALID_HANDLE;
+       *phPrivateKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired key information
+       ByteString prime;
+       ByteString generator;
+       for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++)
+       {
+               switch (pPublicKeyTemplate[i].type)
+               {
+                       case CKA_PRIME:
+                               prime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       case CKA_BASE:
+                               generator = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // The parameters must be specified to be able to generate a key pair.
+       if (prime.size() == 0 || generator.size() == 0) {
+               INFO_MSG("Missing parameter(s) in pPublicKeyTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Extract optional bit length
+       size_t bitLen = 0;
+       for (CK_ULONG i = 0; i < ulPrivateKeyAttributeCount; i++)
+       {
+               switch (pPrivateKeyTemplate[i].type)
+               {
+                       case CKA_VALUE_BITS:
+                               bitLen = *(CK_ULONG*)pPrivateKeyTemplate[i].pValue;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Set the parameters
+       DHParameters p;
+       p.setP(prime);
+       p.setG(generator);
+       p.setXBitLength(bitLen);
+
+       // Generate key pair
+       AsymmetricKeyPair* kp = NULL;
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh == NULL) return CKR_GENERAL_ERROR;
+       if (!dh->generateKeyPair(&kp, &p))
+       {
+               ERROR_MSG("Could not generate key pair");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       DHPublicKey* pub = (DHPublicKey*) kp->getPublicKey();
+       DHPrivateKey* priv = (DHPrivateKey*) kp->getPrivateKey();
+
+       CK_RV rv = CKR_OK;
+
+       // Create a public key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+               CK_KEY_TYPE publicKeyType = CKK_DH;
+               CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) },
+                       { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) },
+                       { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) },
+                       { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) },
+               };
+               CK_ULONG publicKeyAttribsCount = 4;
+
+               // Add the additional
+               if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPublicKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DH_PKCS_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // DH Public Key Attributes
+                               ByteString value;
+                               if (isPublicKeyPrivate)
+                               {
+                                       token->encrypt(pub->getY(), value);
+                               }
+                               else
+                               {
+                                       value = pub->getY();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Create a private key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+               CK_KEY_TYPE privateKeyType = CKK_DH;
+               CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) },
+                       { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) },
+                       { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) },
+                       { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) },
+               };
+               CK_ULONG privateKeyAttribsCount = 4;
+               if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPrivateKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DH_PKCS_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // Common Private Key Attributes
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                               // DH Private Key Attributes
+                               ByteString bPrime;
+                               ByteString bGenerator;
+                               ByteString bValue;
+                               if (isPrivateKeyPrivate)
+                               {
+                                       token->encrypt(priv->getP(), bPrime);
+                                       token->encrypt(priv->getG(), bGenerator);
+                                       token->encrypt(priv->getX(), bValue);
+                               }
+                               else
+                               {
+                                       bPrime = priv->getP();
+                                       bGenerator = priv->getG();
+                                       bValue = priv->getX();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_PRIME, bPrime);
+                               bOK = bOK && osobject->setAttribute(CKA_BASE, bGenerator);
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, bValue);
+
+                               if (bitLen == 0)
+                               {
+                                       bOK = bOK && osobject->setAttribute(CKA_VALUE_BITS, (unsigned long)priv->getX().bits());
+                               }
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Clean up
+       dh->recycleKeyPair(kp);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+       // Remove keys that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phPrivateKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       handleManager->destroyObject(*phPrivateKey);
+                       if (ospriv) ospriv->destroyObject();
+                       *phPrivateKey = CK_INVALID_HANDLE;
+               }
+
+               if (*phPublicKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
+                       handleManager->destroyObject(*phPublicKey);
+                       if (ospub) ospub->destroyObject();
+                       *phPublicKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a DH domain parameter set
+CK_RV SoftHSM::generateDHParameters
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t bitLen = 0;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_PRIME_BITS:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_PRIME_BITS does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               bitLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // CKA_PRIME_BITS must be specified
+       if (bitLen == 0)
+       {
+               INFO_MSG("Missing CKA_PRIME_BITS in pTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Generate domain parameters
+       AsymmetricParameters* p = NULL;
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh == NULL) return CKR_GENERAL_ERROR;
+       if (!dh->generateParameters(&p, (void *)bitLen))
+       {
+               ERROR_MSG("Could not generate parameters");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       DHParameters* params = (DHParameters*) p;
+
+       CK_RV rv = CKR_OK;
+
+       // Create the domain parameter object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_DOMAIN_PARAMETERS;
+       CK_KEY_TYPE keyType = CKK_DH;
+       CK_ATTRIBUTE paramsAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG paramsAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - paramsAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                               continue;
+               default:
+                       paramsAttribs[paramsAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, paramsAttribs, paramsAttribsCount, phKey,OBJECT_OP_GENERATE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                       CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_DH_PKCS_PARAMETER_GEN;
+                       bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                       // DH Domain Parameters Attributes
+                       ByteString prime;
+                       ByteString generator;
+                       if (isPrivate)
+                       {
+                               token->encrypt(params->getP(), prime);
+                               token->encrypt(params->getG(), generator);
+                       }
+                       else
+                       {
+                               prime = params->getP();
+                               generator = params->getG();
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_PRIME, prime);
+                       bOK = bOK && osobject->setAttribute(CKA_BASE, generator);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       dh->recycleParameters(p);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+       // Remove parameters that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* osparams = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (osparams) osparams->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Generate a GOST key pair
+CK_RV SoftHSM::generateGOST
+(CK_SESSION_HANDLE hSession,
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+       CK_ULONG ulPublicKeyAttributeCount,
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey,
+       CK_OBJECT_HANDLE_PTR phPrivateKey,
+       CK_BBOOL isPublicKeyOnToken,
+       CK_BBOOL isPublicKeyPrivate,
+       CK_BBOOL isPrivateKeyOnToken,
+       CK_BBOOL isPrivateKeyPrivate)
+{
+       *phPublicKey = CK_INVALID_HANDLE;
+       *phPrivateKey = CK_INVALID_HANDLE;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired key information
+       ByteString param_3410;
+       ByteString param_3411;
+       ByteString param_28147;
+       for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++)
+       {
+               switch (pPublicKeyTemplate[i].type)
+               {
+                       case CKA_GOSTR3410_PARAMS:
+                               param_3410 = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       case CKA_GOSTR3411_PARAMS:
+                               param_3411 = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       case CKA_GOST28147_PARAMS:
+                               param_28147 = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // The parameters must be specified to be able to generate a key pair.
+       if (param_3410.size() == 0 || param_3411.size() == 0) {
+               INFO_MSG("Missing parameter(s) in pPublicKeyTemplate");
+               return CKR_TEMPLATE_INCOMPLETE;
+       }
+
+       // Set the parameters
+       ECParameters p;
+       p.setEC(param_3410);
+
+       // Generate key pair
+       AsymmetricKeyPair* kp = NULL;
+       AsymmetricAlgorithm* gost = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST);
+       if (gost == NULL) return CKR_GENERAL_ERROR;
+       if (!gost->generateKeyPair(&kp, &p))
+       {
+               ERROR_MSG("Could not generate key pair");
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(gost);
+               return CKR_GENERAL_ERROR;
+       }
+
+       GOSTPublicKey* pub = (GOSTPublicKey*) kp->getPublicKey();
+       GOSTPrivateKey* priv = (GOSTPrivateKey*) kp->getPrivateKey();
+
+       CK_RV rv = CKR_OK;
+
+       // Create a public key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY;
+               CK_KEY_TYPE publicKeyType = CKK_GOSTR3410;
+               CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) },
+                       { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) },
+                       { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) },
+                       { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) },
+               };
+               CK_ULONG publicKeyAttribsCount = 4;
+
+               // Add the additional
+               if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPublicKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // EC Public Key Attributes
+                               ByteString point;
+                               if (isPublicKeyPrivate)
+                               {
+                                       token->encrypt(pub->getQ(), point);
+                               }
+                               else
+                               {
+                                       point = pub->getQ();
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, point);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                               rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Create a private key using C_CreateObject
+       if (rv == CKR_OK)
+       {
+               const CK_ULONG maxAttribs = 32;
+               CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY;
+               CK_KEY_TYPE privateKeyType = CKK_GOSTR3410;
+               CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = {
+                       { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) },
+                       { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) },
+                       { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) },
+                       { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) },
+               };
+               CK_ULONG privateKeyAttribsCount = 4;
+               if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount))
+                       rv = CKR_TEMPLATE_INCONSISTENT;
+               for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i)
+               {
+                       switch (pPrivateKeyTemplate[i].type)
+                       {
+                               case CKA_CLASS:
+                               case CKA_TOKEN:
+                               case CKA_PRIVATE:
+                               case CKA_KEY_TYPE:
+                                       continue;
+                               default:
+                                       privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i];
+                       }
+               }
+
+               if (rv == CKR_OK)
+                       rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE);
+
+               // Store the attributes that are being supplied by the key generation to the object
+               if (rv == CKR_OK)
+               {
+                       OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       if (osobject == NULL_PTR || !osobject->isValid()) {
+                               rv = CKR_FUNCTION_FAILED;
+                       } else if (osobject->startTransaction()) {
+                               bool bOK = true;
+
+                               // Common Key Attributes
+                               bOK = bOK && osobject->setAttribute(CKA_LOCAL,true);
+                               CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_KEY_PAIR_GEN;
+                               bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism);
+
+                               // Common Private Key Attributes
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
+
+                               // GOST Private Key Attributes
+                               ByteString value;
+                               ByteString param_a;
+                               ByteString param_b;
+                               ByteString param_c;
+                               if (isPrivateKeyPrivate)
+                               {
+                                       token->encrypt(priv->getD(), value);
+                                       token->encrypt(priv->getEC(), param_a);
+                                       token->encrypt(param_3411, param_b);
+                                       token->encrypt(param_28147, param_c);
+                               }
+                               else
+                               {
+                                       value = priv->getD();
+                                       param_a = priv->getEC();
+                                       param_b = param_3411;
+                                       param_c = param_28147;
+                               }
+                               bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                               bOK = bOK && osobject->setAttribute(CKA_GOSTR3410_PARAMS, param_a);
+                               bOK = bOK && osobject->setAttribute(CKA_GOSTR3411_PARAMS, param_b);
+                               bOK = bOK && osobject->setAttribute(CKA_GOST28147_PARAMS, param_c);
+
+                               if (bOK)
+                                       bOK = osobject->commitTransaction();
+                               else
+                                       osobject->abortTransaction();
+
+                               if (!bOK)
+                                       rv = CKR_FUNCTION_FAILED;
+                       } else
+                                 rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       // Clean up
+       gost->recycleKeyPair(kp);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(gost);
+
+       // Remove keys that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phPrivateKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey);
+                       handleManager->destroyObject(*phPrivateKey);
+                       if (ospriv) ospriv->destroyObject();
+                       *phPrivateKey = CK_INVALID_HANDLE;
+               }
+
+               if (*phPublicKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
+                       handleManager->destroyObject(*phPublicKey);
+                       if (ospub) ospub->destroyObject();
+                       *phPublicKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Derive a DH secret
+CK_RV SoftHSM::deriveDH
+(CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hBaseKey,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_KEY_TYPE keyType,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       if (pMechanism->pParameter == NULL_PTR) return CKR_MECHANISM_PARAM_INVALID;
+       if (pMechanism->ulParameterLen == 0) return CKR_MECHANISM_PARAM_INVALID;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t byteLen = 0;
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_VALUE:
+                               INFO_MSG("CKA_VALUE must not be included");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       case CKA_VALUE_LEN:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               byteLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Check the length
+       switch (keyType)
+       {
+               case CKK_GENERIC_SECRET:
+                       if (byteLen == 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be set");
+                               return CKR_TEMPLATE_INCOMPLETE;
+                       }
+                       break;
+#ifndef WITH_FIPS
+               case CKK_DES:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 8;
+                       break;
+#endif
+               case CKK_DES2:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 16;
+                       break;
+               case CKK_DES3:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 24;
+                       break;
+               case CKK_AES:
+                       if (byteLen != 16 && byteLen != 24 && byteLen != 32)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 16, 24, or 32");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       break;
+               default:
+                       return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Get the base key handle
+       OSObject *baseKey = (OSObject *)handleManager->getObject(hBaseKey);
+       if (baseKey == NULL || !baseKey->isValid())
+               return CKR_KEY_HANDLE_INVALID;
+
+       // Get the DH algorithm handler
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh == NULL)
+               return CKR_MECHANISM_INVALID;
+
+       // Get the keys
+       PrivateKey* privateKey = dh->newPrivateKey();
+       if (privateKey == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getDHPrivateKey((DHPrivateKey*)privateKey, token, baseKey) != CKR_OK)
+       {
+               dh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       ByteString mechParameters;
+       mechParameters.resize(pMechanism->ulParameterLen);
+       memcpy(&mechParameters[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+       PublicKey* publicKey = dh->newPublicKey();
+       if (publicKey == NULL)
+       {
+               dh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getDHPublicKey((DHPublicKey*)publicKey, (DHPrivateKey*)privateKey, mechParameters) != CKR_OK)
+       {
+               dh->recyclePrivateKey(privateKey);
+               dh->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Derive the secret
+       SymmetricKey* secret = NULL;
+       CK_RV rv = CKR_OK;
+       if (!dh->deriveKey(&secret, publicKey, privateKey))
+               rv = CKR_GENERAL_ERROR;
+       dh->recyclePrivateKey(privateKey);
+       dh->recyclePublicKey(publicKey);
+
+       // Create the secret object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_ATTRIBUTE secretAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG secretAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - secretAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       secretAttribs[secretAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, phKey, OBJECT_OP_DERIVE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,false);
+
+                       // Common Secret Key Attributes
+                       if (baseKey->getBooleanValue(CKA_ALWAYS_SENSITIVE, false))
+                       {
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,false);
+                       }
+                       if (baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, true))
+                       {
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,bNeverExtractable);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,false);
+                       }
+
+                       // Secret Attributes
+                       ByteString secretValue = secret->getKeyBits();
+                       ByteString value;
+                       ByteString plainKCV;
+                       ByteString kcv;
+
+                       if (byteLen > secretValue.size())
+                       {
+                               INFO_MSG("The derived secret is too short");
+                               bOK = false;
+                       }
+                       else
+                       {
+                               // Truncate value when requested, remove from the leading end
+                               if (byteLen < secretValue.size())
+                                       secretValue.split(secretValue.size() - byteLen);
+
+                               // Fix the odd parity for DES
+                               if (keyType == CKK_DES ||
+                                   keyType == CKK_DES2 ||
+                                   keyType == CKK_DES3)
+                               {
+                                       for (size_t i = 0; i < secretValue.size(); i++)
+                                       {
+                                               secretValue[i] = odd_parity[secretValue[i]];
+                                       }
+                               }
+
+                               // Get the KCV
+                               switch (keyType)
+                               {
+                                       case CKK_GENERIC_SECRET:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = secret->getKeyCheckValue();
+                                               break;
+                                       case CKK_DES:
+                                       case CKK_DES2:
+                                       case CKK_DES3:
+                                               secret->setBitLen(byteLen * 7);
+                                               plainKCV = ((DESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       case CKK_AES:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = ((AESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       default:
+                                               bOK = false;
+                                               break;
+                               }
+
+                               if (isPrivate)
+                               {
+                                       token->encrypt(secretValue, value);
+                                       token->encrypt(plainKCV, kcv);
+                               }
+                               else
+                               {
+                                       value = secretValue;
+                                       kcv = plainKCV;
+                               }
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       dh->recycleSymmetricKey(secret);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+       // Remove secret that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (ossecret) ossecret->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+// Derive an ECDH secret
+CK_RV SoftHSM::deriveECDH
+(CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hBaseKey,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_KEY_TYPE keyType,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+#ifdef WITH_ECC
+       *phKey = CK_INVALID_HANDLE;
+
+       if ((pMechanism->pParameter == NULL_PTR) ||
+           (pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)))
+       {
+               DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+       if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL)
+       {
+               DEBUG_MSG("kdf must be CKD_NULL");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+       if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) ||
+           (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR))
+       {
+               DEBUG_MSG("there must be no shared data");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+       if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) ||
+           (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR))
+       {
+               DEBUG_MSG("there must be a public data");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t byteLen = 0;
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_VALUE:
+                               INFO_MSG("CKA_VALUE must not be included");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       case CKA_VALUE_LEN:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               byteLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Check the length
+       // byteLen == 0 impiles return max size the ECC can derive
+       switch (keyType)
+       {
+               case CKK_GENERIC_SECRET:
+                       break;
+#ifndef WITH_FIPS
+               case CKK_DES:
+                       if (byteLen != 0 && byteLen != 8)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 0 or 8");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       byteLen = 8;
+                       break;
+#endif
+               case CKK_DES2:
+                       if (byteLen != 0 && byteLen != 16)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 0 or 16");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       byteLen = 16;
+                       break;
+               case CKK_DES3:
+                       if (byteLen != 0 && byteLen != 24)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 0 or 24");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       byteLen = 24;
+                       break;
+               case CKK_AES:
+                       if (byteLen != 0 && byteLen != 16 && byteLen != 24 && byteLen != 32)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 0, 16, 24, or 32");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       break;
+               default:
+                       return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Get the base key handle
+       OSObject *baseKey = (OSObject *)handleManager->getObject(hBaseKey);
+       if (baseKey == NULL || !baseKey->isValid())
+               return CKR_KEY_HANDLE_INVALID;
+
+       // Get the ECDH algorithm handler
+       AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH);
+       if (ecdh == NULL)
+               return CKR_MECHANISM_INVALID;
+
+       // Get the keys
+       PrivateKey* privateKey = ecdh->newPrivateKey();
+       if (privateKey == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getECPrivateKey((ECPrivateKey*)privateKey, token, baseKey) != CKR_OK)
+       {
+               ecdh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       ByteString publicData;
+       publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
+       memcpy(&publicData[0],
+              CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
+              CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
+       PublicKey* publicKey = ecdh->newPublicKey();
+       if (publicKey == NULL)
+       {
+               ecdh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getECDHPublicKey((ECPublicKey*)publicKey, (ECPrivateKey*)privateKey, publicData) != CKR_OK)
+       {
+               ecdh->recyclePrivateKey(privateKey);
+               ecdh->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Derive the secret
+       SymmetricKey* secret = NULL;
+       CK_RV rv = CKR_OK;
+       if (!ecdh->deriveKey(&secret, publicKey, privateKey))
+               rv = CKR_GENERAL_ERROR;
+       ecdh->recyclePrivateKey(privateKey);
+       ecdh->recyclePublicKey(publicKey);
+
+       // Create the secret object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_ATTRIBUTE secretAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG secretAttribsCount = 4;
+
+       // Add the additional
+       if (ulCount > (maxAttribs - secretAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+               default:
+                       secretAttribs[secretAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, phKey, OBJECT_OP_DERIVE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,false);
+
+                       // Common Secret Key Attributes
+                       if (baseKey->getBooleanValue(CKA_ALWAYS_SENSITIVE, false))
+                       {
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,false);
+                       }
+                       if (baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, true))
+                       {
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,bNeverExtractable);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,false);
+                       }
+
+                       // Secret Attributes
+                       ByteString secretValue = secret->getKeyBits();
+                       ByteString value;
+                       ByteString plainKCV;
+                       ByteString kcv;
+
+                       // For generic and AES keys:
+                       // default to return max size available.
+                       if (byteLen == 0)
+                       {
+                               switch (keyType)
+                               {
+                                       case CKK_GENERIC_SECRET:
+                                               byteLen = secretValue.size();
+                                               break;
+                                       case CKK_AES:
+                                               if (secretValue.size() >= 32)
+                                                       byteLen = 32;
+                                               else if (secretValue.size() >= 24)
+                                                       byteLen = 24;
+                                               else
+                                                       byteLen = 16;
+                               }
+                       }
+
+                       if (byteLen > secretValue.size())
+                       {
+                               INFO_MSG("The derived secret is too short");
+                               bOK = false;
+                       }
+                       else
+                       {
+                               // Truncate value when requested, remove from the leading end
+                               if (byteLen < secretValue.size())
+                                       secretValue.split(secretValue.size() - byteLen);
+
+                               // Fix the odd parity for DES
+                               if (keyType == CKK_DES ||
+                                   keyType == CKK_DES2 ||
+                                   keyType == CKK_DES3)
+                               {
+                                       for (size_t i = 0; i < secretValue.size(); i++)
+                                       {
+                                               secretValue[i] = odd_parity[secretValue[i]];
+                                       }
+                               }
+
+                               // Get the KCV
+                               switch (keyType)
+                               {
+                                       case CKK_GENERIC_SECRET:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = secret->getKeyCheckValue();
+                                               break;
+                                       case CKK_DES:
+                                       case CKK_DES2:
+                                       case CKK_DES3:
+                                               secret->setBitLen(byteLen * 7);
+                                               plainKCV = ((DESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       case CKK_AES:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = ((AESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       default:
+                                               bOK = false;
+                                               break;
+                               }
+
+                               if (isPrivate)
+                               {
+                                       token->encrypt(secretValue, value);
+                                       token->encrypt(plainKCV, kcv);
+                               }
+                               else
+                               {
+                                       value = secretValue;
+                                       kcv = plainKCV;
+                               }
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Clean up
+       ecdh->recycleSymmetricKey(secret);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+
+       // Remove secret that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (ossecret) ossecret->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+#else
+       return CKR_MECHANISM_INVALID;
+#endif
+}
+
+// Derive an symmetric secret
+CK_RV SoftHSM::deriveSymmetric
+(CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism,
+       CK_OBJECT_HANDLE hBaseKey,
+       CK_ATTRIBUTE_PTR pTemplate,
+       CK_ULONG ulCount,
+       CK_OBJECT_HANDLE_PTR phKey,
+       CK_KEY_TYPE keyType,
+       CK_BBOOL isOnToken,
+       CK_BBOOL isPrivate)
+{
+       *phKey = CK_INVALID_HANDLE;
+
+       if (pMechanism->pParameter == NULL_PTR)
+       {
+               DEBUG_MSG("pParameter must be supplied");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+
+       ByteString data;
+
+       if ((pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA ||
+           pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA) &&
+           pMechanism->ulParameterLen == sizeof(CK_KEY_DERIVATION_STRING_DATA))
+       {
+               CK_BYTE_PTR pData = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->pData;
+               CK_ULONG ulLen = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->ulLen;
+               if (ulLen == 0 || pData == NULL_PTR)
+               {
+                       DEBUG_MSG("There must be data in the parameter");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               if (ulLen % 8 != 0)
+               {
+                       DEBUG_MSG("The data must be a multiple of 8 bytes long");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               data.resize(ulLen);
+               memcpy(&data[0],
+                      pData,
+                      ulLen);
+       }
+       else if ((pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA ||
+                pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA) &&
+                pMechanism->ulParameterLen == sizeof(CK_DES_CBC_ENCRYPT_DATA_PARAMS))
+       {
+               CK_BYTE_PTR pData = CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->pData;
+               CK_ULONG length = CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->length;
+               if (length == 0 || pData == NULL_PTR)
+               {
+                       DEBUG_MSG("There must be data in the parameter");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               if (length % 8 != 0)
+               {
+                       DEBUG_MSG("The data must be a multiple of 8 bytes long");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               data.resize(length);
+               memcpy(&data[0],
+                      pData,
+                      length);
+       }
+       else if (pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA &&
+                pMechanism->ulParameterLen == sizeof(CK_KEY_DERIVATION_STRING_DATA))
+       {
+               CK_BYTE_PTR pData = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->pData;
+               CK_ULONG ulLen = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->ulLen;
+               if (ulLen == 0 || pData == NULL_PTR)
+               {
+                       DEBUG_MSG("There must be data in the parameter");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               if (ulLen % 16 != 0)
+               {
+                       DEBUG_MSG("The data must be a multiple of 16 bytes long");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               data.resize(ulLen);
+               memcpy(&data[0],
+                      pData,
+                      ulLen);
+       }
+       else if ((pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA) &&
+                pMechanism->ulParameterLen == sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))
+       {
+               CK_BYTE_PTR pData = CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->pData;
+               CK_ULONG length = CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->length;
+               if (length == 0 || pData == NULL_PTR)
+               {
+                       DEBUG_MSG("There must be data in the parameter");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               if (length % 16 != 0)
+               {
+                       DEBUG_MSG("The data must be a multiple of 16 bytes long");
+                       return CKR_MECHANISM_PARAM_INVALID;
+               }
+               data.resize(length);
+               memcpy(&data[0],
+                      pData,
+                      length);
+       }
+       else
+       {
+               DEBUG_MSG("pParameter is invalid");
+               return CKR_MECHANISM_PARAM_INVALID;
+       }
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL)
+               return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL)
+               return CKR_GENERAL_ERROR;
+
+       // Extract desired parameter information
+       size_t byteLen = 0;
+       bool checkValue = true;
+       for (CK_ULONG i = 0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_VALUE:
+                               INFO_MSG("CKA_VALUE must not be included");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       case CKA_VALUE_LEN:
+                               if (pTemplate[i].ulValueLen != sizeof(CK_ULONG))
+                               {
+                                       INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               byteLen = *(CK_ULONG*)pTemplate[i].pValue;
+                               break;
+                       case CKA_CHECK_VALUE:
+                               if (pTemplate[i].ulValueLen > 0)
+                               {
+                                       INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry");
+                                       return CKR_ATTRIBUTE_VALUE_INVALID;
+                               }
+                               checkValue = false;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       // Check the length
+       switch (keyType)
+       {
+               case CKK_GENERIC_SECRET:
+                       if (byteLen == 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be set");
+                               return CKR_TEMPLATE_INCOMPLETE;
+                       }
+                       break;
+#ifndef WITH_FIPS
+               case CKK_DES:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 8;
+                       break;
+#endif
+               case CKK_DES2:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 16;
+                       break;
+               case CKK_DES3:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 24;
+                       break;
+               case CKK_AES:
+                       if (byteLen != 16 && byteLen != 24 && byteLen != 32)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 16, 24, or 32");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
+                       }
+                       break;
+               default:
+                       return CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       // Get the symmetric algorithm matching the mechanism
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       SymMode::Type mode = SymMode::Unknown;
+       bool padding = false;
+       ByteString iv;
+       size_t bb = 8;
+       switch(pMechanism->mechanism) {
+#ifndef WITH_FIPS
+               case CKM_DES_ECB_ENCRYPT_DATA:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES_CBC_ENCRYPT_DATA:
+                       algo = SymAlgo::DES;
+                       mode = SymMode::CBC;
+                       bb = 7;
+                       iv.resize(8);
+                       memcpy(&iv[0],
+                              &(CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]),
+                              8);
+                       break;
+#endif
+               case CKM_DES3_ECB_ENCRYPT_DATA:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::ECB;
+                       bb = 7;
+                       break;
+               case CKM_DES3_CBC_ENCRYPT_DATA:
+                       algo = SymAlgo::DES3;
+                       mode = SymMode::CBC;
+                       bb = 7;
+                       iv.resize(8);
+                       memcpy(&iv[0],
+                              &(CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]),
+                              8);
+                       break;
+               case CKM_AES_ECB_ENCRYPT_DATA:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::ECB;
+                       break;
+               case CKM_AES_CBC_ENCRYPT_DATA:
+                       algo = SymAlgo::AES;
+                       mode = SymMode::CBC;
+                       iv.resize(16);
+                       memcpy(&iv[0],
+                              &(CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]),
+                              16);
+                       break;
+               default:
+                       return CKR_MECHANISM_INVALID;
+       }
+
+       // Check the key handle
+       OSObject *baseKey = (OSObject *)handleManager->getObject(hBaseKey);
+       if (baseKey == NULL_PTR || !baseKey->isValid()) return CKR_OBJECT_HANDLE_INVALID;
+
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return CKR_MECHANISM_INVALID;
+
+       SymmetricKey* secretkey = new SymmetricKey();
+
+       if (getSymmetricKey(secretkey, token, baseKey) != CKR_OK)
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // adjust key bit length
+       secretkey->setBitLen(secretkey->getKeyBits().size() * bb);
+
+       // Initialize encryption
+       if (!cipher->encryptInit(secretkey, mode, iv, padding))
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_MECHANISM_INVALID;
+       }
+
+       // Get the data
+       ByteString secretValue;
+
+       // Encrypt the data
+       if (!cipher->encryptUpdate(data, secretValue))
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Finalize encryption
+       ByteString encryptedFinal;
+       if (!cipher->encryptFinal(encryptedFinal))
+       {
+               cipher->recycleKey(secretkey);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return CKR_GENERAL_ERROR;
+       }
+       cipher->recycleKey(secretkey);
+       CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+       secretValue += encryptedFinal;
+
+       // Create the secret object using C_CreateObject
+       const CK_ULONG maxAttribs = 32;
+       CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
+       CK_ATTRIBUTE secretAttribs[maxAttribs] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_TOKEN, &isOnToken, sizeof(isOnToken) },
+               { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+       };
+       CK_ULONG secretAttribsCount = 4;
+
+       // Add the additional
+       CK_RV rv = CKR_OK;
+       if (ulCount > (maxAttribs - secretAttribsCount))
+               rv = CKR_TEMPLATE_INCONSISTENT;
+       for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CLASS:
+                       case CKA_TOKEN:
+                       case CKA_PRIVATE:
+                       case CKA_KEY_TYPE:
+                       case CKA_CHECK_VALUE:
+                               continue;
+                       default:
+                               secretAttribs[secretAttribsCount++] = pTemplate[i];
+               }
+       }
+
+       if (rv == CKR_OK)
+               rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, phKey, OBJECT_OP_DERIVE);
+
+       // Store the attributes that are being supplied
+       if (rv == CKR_OK)
+       {
+               OSObject* osobject = (OSObject*)handleManager->getObject(*phKey);
+               if (osobject == NULL_PTR || !osobject->isValid()) {
+                       rv = CKR_FUNCTION_FAILED;
+               } else if (osobject->startTransaction()) {
+                       bool bOK = true;
+
+                       // Common Attributes
+                       bOK = bOK && osobject->setAttribute(CKA_LOCAL,false);
+
+                       // Common Secret Key Attributes
+                       if (baseKey->getBooleanValue(CKA_ALWAYS_SENSITIVE, false))
+                       {
+                               bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false);
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,false);
+                       }
+                       if (baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, true))
+                       {
+                               bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false;
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,bNeverExtractable);
+                       }
+                       else
+                       {
+                               bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,false);
+                       }
+
+                       ByteString value;
+                       ByteString plainKCV;
+                       ByteString kcv;
+
+                       if (byteLen > secretValue.size())
+                       {
+                               INFO_MSG("The derived secret is too short");
+                               bOK = false;
+                       }
+                       else
+                       {
+                               // Truncate value when requested, remove from the trailing end
+                               if (byteLen < secretValue.size())
+                                       secretValue.resize(byteLen);
+
+                               // Fix the odd parity for DES
+                               if (keyType == CKK_DES ||
+                                   keyType == CKK_DES2 ||
+                                   keyType == CKK_DES3)
+                               {
+                                       for (size_t i = 0; i < secretValue.size(); i++)
+                                       {
+                                               secretValue[i] = odd_parity[secretValue[i]];
+                                       }
+                               }
+
+                               // Get the KCV
+                               SymmetricKey* secret = new SymmetricKey();
+                               secret->setKeyBits(secretValue);
+                               switch (keyType)
+                               {
+                                       case CKK_GENERIC_SECRET:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = secret->getKeyCheckValue();
+                                               break;
+                                       case CKK_DES:
+                                       case CKK_DES2:
+                                       case CKK_DES3:
+                                               secret->setBitLen(byteLen * 7);
+                                               plainKCV = ((DESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       case CKK_AES:
+                                               secret->setBitLen(byteLen * 8);
+                                               plainKCV = ((AESKey*)secret)->getKeyCheckValue();
+                                               break;
+                                       default:
+                                               bOK = false;
+                                               break;
+                               }
+                               delete secret;
+
+                               if (isPrivate)
+                               {
+                                       token->encrypt(secretValue, value);
+                                       token->encrypt(plainKCV, kcv);
+                               }
+                               else
+                               {
+                                       value = secretValue;
+                                       kcv = plainKCV;
+                               }
+                       }
+                       bOK = bOK && osobject->setAttribute(CKA_VALUE, value);
+                       if (checkValue)
+                               bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv);
+
+                       if (bOK)
+                               bOK = osobject->commitTransaction();
+                       else
+                               osobject->abortTransaction();
+
+                       if (!bOK)
+                               rv = CKR_FUNCTION_FAILED;
+               } else
+                       rv = CKR_FUNCTION_FAILED;
+       }
+
+       // Remove secret that may have been created already when the function fails.
+       if (rv != CKR_OK)
+       {
+               if (*phKey != CK_INVALID_HANDLE)
+               {
+                       OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (ossecret) ossecret->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
+               }
+       }
+
+       return rv;
+}
+
+CK_RV SoftHSM::CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject, int op)
+{
+       if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (phObject == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Get the session
+       Session* session = (Session*)handleManager->getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Get the slot
+       Slot* slot = session->getSlot();
+       if (slot == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Get the token
+       Token* token = session->getToken();
+       if (token == NULL_PTR) return CKR_GENERAL_ERROR;
+
+       // Extract information from the template that is needed to create the object.
+       CK_OBJECT_CLASS objClass = CKO_DATA;
+       CK_KEY_TYPE keyType = CKK_RSA;
+       CK_CERTIFICATE_TYPE certType = CKC_X_509;
+       CK_BBOOL isOnToken = CK_FALSE;
+       CK_BBOOL isPrivate = CK_TRUE;
+       bool isImplicit = false;
+       CK_RV rv = extractObjectInformation(pTemplate,ulCount,objClass,keyType,certType, isOnToken, isPrivate, isImplicit);
+       if (rv != CKR_OK)
+       {
+               ERROR_MSG("Mandatory attribute not present in template");
+               return rv;
+       }
+
+       // Check user credentials
+       rv = haveWrite(session->getState(), isOnToken, isPrivate);
+       if (rv != CKR_OK)
+       {
+               if (rv == CKR_USER_NOT_LOGGED_IN)
+                       INFO_MSG("User is not authorized");
+               if (rv == CKR_SESSION_READ_ONLY)
+                       INFO_MSG("Session is read-only");
+
+               return rv;
+       }
+
+       // Change order of attributes
+       const CK_ULONG maxAttribs = 32;
+       CK_ATTRIBUTE attribs[maxAttribs];
+       CK_ATTRIBUTE saveAttribs[maxAttribs];
+       CK_ULONG attribsCount = 0;
+       CK_ULONG saveAttribsCount = 0;
+       if (ulCount > maxAttribs)
+       {
+               return CKR_TEMPLATE_INCONSISTENT;
+       }
+       for (CK_ULONG i=0; i < ulCount; i++)
+       {
+               switch (pTemplate[i].type)
+               {
+                       case CKA_CHECK_VALUE:
+                               saveAttribs[saveAttribsCount++] = pTemplate[i];
+                               break;
+                       default:
+                               attribs[attribsCount++] = pTemplate[i];
+               }
+       }
+       for (CK_ULONG i=0; i < saveAttribsCount; i++)
+       {
+               attribs[attribsCount++] = saveAttribs[i];
+       }
+
+       P11Object* p11object = NULL;
+       rv = newP11Object(objClass,keyType,certType,&p11object);
+       if (rv != CKR_OK)
+               return rv;
+
+       // Create the object in session or on the token
+       OSObject *object = NULL_PTR;
+       if (isOnToken)
+       {
+               object = (OSObject*) token->createObject();
+       }
+       else
+       {
+               object = sessionObjectStore->createObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE);
+       }
+
+       if (object == NULL || !p11object->init(object))
+       {
+               delete p11object;
+               return CKR_GENERAL_ERROR;
+       }
+
+       rv = p11object->saveTemplate(token, isPrivate != CK_FALSE, attribs,attribsCount,op);
+       delete p11object;
+       if (rv != CKR_OK)
+               return rv;
+
+       if (op == OBJECT_OP_CREATE)
+       {
+               if (objClass == CKO_PUBLIC_KEY &&
+                   (!object->startTransaction() ||
+                   !object->setAttribute(CKA_LOCAL, false) ||
+                   !object->commitTransaction()))
+               {
+                       return CKR_GENERAL_ERROR;
+               }
+
+               if ((objClass == CKO_SECRET_KEY || objClass == CKO_PRIVATE_KEY) &&
+                   (!object->startTransaction() ||
+                   !object->setAttribute(CKA_LOCAL, false) ||
+                   !object->setAttribute(CKA_ALWAYS_SENSITIVE, false) ||
+                   !object->setAttribute(CKA_NEVER_EXTRACTABLE, false) ||
+                   !object->commitTransaction()))
+               {
+                       return CKR_GENERAL_ERROR;
+               }
+       }
+
+       if (isOnToken)
+       {
+               *phObject = handleManager->addTokenObject(slot->getSlotID(), isPrivate != CK_FALSE, object);
+       } else {
+               *phObject = handleManager->addSessionObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE, object);
+       }
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getRSAPrivateKey(RSAPrivateKey* privateKey, Token* token, OSObject* key)
+{
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // RSA Private Key Attributes
+       ByteString modulus;
+       ByteString publicExponent;
+       ByteString privateExponent;
+       ByteString prime1;
+       ByteString prime2;
+       ByteString exponent1;
+       ByteString exponent2;
+       ByteString coefficient;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_MODULUS), modulus);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PUBLIC_EXPONENT), publicExponent);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIVATE_EXPONENT), privateExponent);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME_1), prime1);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME_2), prime2);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EXPONENT_1), exponent1);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EXPONENT_2), exponent2);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_COEFFICIENT), coefficient);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               modulus = key->getByteStringValue(CKA_MODULUS);
+               publicExponent = key->getByteStringValue(CKA_PUBLIC_EXPONENT);
+               privateExponent = key->getByteStringValue(CKA_PRIVATE_EXPONENT);
+               prime1 = key->getByteStringValue(CKA_PRIME_1);
+               prime2 = key->getByteStringValue(CKA_PRIME_2);
+               exponent1 =  key->getByteStringValue(CKA_EXPONENT_1);
+               exponent2 = key->getByteStringValue(CKA_EXPONENT_2);
+               coefficient = key->getByteStringValue(CKA_COEFFICIENT);
+       }
+
+       privateKey->setN(modulus);
+       privateKey->setE(publicExponent);
+       privateKey->setD(privateExponent);
+       privateKey->setP(prime1);
+       privateKey->setQ(prime2);
+       privateKey->setDP1(exponent1);
+       privateKey->setDQ1(exponent2);
+       privateKey->setPQ(coefficient);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getRSAPublicKey(RSAPublicKey* publicKey, Token* token, OSObject* key)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // RSA Public Key Attributes
+       ByteString modulus;
+       ByteString publicExponent;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_MODULUS), modulus);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PUBLIC_EXPONENT), publicExponent);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               modulus = key->getByteStringValue(CKA_MODULUS);
+               publicExponent = key->getByteStringValue(CKA_PUBLIC_EXPONENT);
+       }
+
+       publicKey->setN(modulus);
+       publicKey->setE(publicExponent);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getDSAPrivateKey(DSAPrivateKey* privateKey, Token* token, OSObject* key)
+{
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // DSA Private Key Attributes
+       ByteString prime;
+       ByteString subprime;
+       ByteString generator;
+       ByteString value;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_SUBPRIME), subprime);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               prime = key->getByteStringValue(CKA_PRIME);
+               subprime = key->getByteStringValue(CKA_SUBPRIME);
+               generator = key->getByteStringValue(CKA_BASE);
+               value = key->getByteStringValue(CKA_VALUE);
+       }
+
+       privateKey->setP(prime);
+       privateKey->setQ(subprime);
+       privateKey->setG(generator);
+       privateKey->setX(value);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getDSAPublicKey(DSAPublicKey* publicKey, Token* token, OSObject* key)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // DSA Public Key Attributes
+       ByteString prime;
+       ByteString subprime;
+       ByteString generator;
+       ByteString value;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_SUBPRIME), subprime);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               prime = key->getByteStringValue(CKA_PRIME);
+               subprime = key->getByteStringValue(CKA_SUBPRIME);
+               generator = key->getByteStringValue(CKA_BASE);
+               value = key->getByteStringValue(CKA_VALUE);
+       }
+
+       publicKey->setP(prime);
+       publicKey->setQ(subprime);
+       publicKey->setG(generator);
+       publicKey->setY(value);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getECPrivateKey(ECPrivateKey* privateKey, Token* token, OSObject* key)
+{
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // EC Private Key Attributes
+       ByteString group;
+       ByteString value;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_PARAMS), group);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               group = key->getByteStringValue(CKA_EC_PARAMS);
+               value = key->getByteStringValue(CKA_VALUE);
+       }
+
+       privateKey->setEC(group);
+       privateKey->setD(value);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getECPublicKey(ECPublicKey* publicKey, Token* token, OSObject* key)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // EC Public Key Attributes
+       ByteString group;
+       ByteString point;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_PARAMS), group);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_POINT), point);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               group = key->getByteStringValue(CKA_EC_PARAMS);
+               point = key->getByteStringValue(CKA_EC_POINT);
+       }
+
+       publicKey->setEC(group);
+       publicKey->setQ(point);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getDHPrivateKey(DHPrivateKey* privateKey, Token* token, OSObject* key)
+{
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // DH Private Key Attributes
+       ByteString prime;
+       ByteString generator;
+       ByteString value;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               prime = key->getByteStringValue(CKA_PRIME);
+               generator = key->getByteStringValue(CKA_BASE);
+               value = key->getByteStringValue(CKA_VALUE);
+       }
+
+       privateKey->setP(prime);
+       privateKey->setG(generator);
+       privateKey->setX(value);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getDHPublicKey(DHPublicKey* publicKey, DHPrivateKey* privateKey, ByteString& pubParams)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Copy Domain Parameters from Private Key
+       publicKey->setP(privateKey->getP());
+       publicKey->setG(privateKey->getG());
+
+       // Set value
+       publicKey->setY(pubParams);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getECDHPublicKey(ECPublicKey* publicKey, ECPrivateKey* privateKey, ByteString& pubData)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Copy Domain Parameters from Private Key
+       publicKey->setEC(privateKey->getEC());
+
+       // Set value
+       ByteString data = getECDHPubData(pubData);
+       publicKey->setQ(data);
+
+       return CKR_OK;
+}
+
+// ECDH pubData can be in RAW or DER format.
+// Need to convert RAW as SoftHSM uses DER.
+ByteString SoftHSM::getECDHPubData(ByteString& pubData)
+{
+       size_t len = pubData.size();
+       size_t controlOctets = 2;
+       if (len == 65 || len == 97 || len == 133)
+       {
+               // Raw: Length matches the public key size of P-256, P-384, or P-521
+               controlOctets = 0;
+       }
+       else if (len < controlOctets || pubData[0] != 0x04)
+       {
+               // Raw: Too short or does not start with 0x04
+               controlOctets = 0;
+       }
+       else if (pubData[1] < 0x80)
+       {
+               // Raw: Length octet does not match remaining data length
+               if (pubData[1] != (len - controlOctets)) controlOctets = 0;
+       }
+       else
+       {
+               size_t lengthOctets = pubData[1] & 0x7F;
+               controlOctets += lengthOctets;
+
+               if (controlOctets >= len)
+               {
+                       // Raw: Too short
+                       controlOctets = 0;
+               }
+               else
+               {
+                       ByteString length(&pubData[2], lengthOctets);
+
+                       if (length.long_val() != (len - controlOctets))
+                       {
+                               // Raw: Length octets does not match remaining data length
+                               controlOctets = 0;
+                       }
+               }
+       }
+
+       // DER format
+       if (controlOctets != 0) return pubData;
+
+       // RAW format
+       ByteString header;
+       if (len < 0x80)
+       {
+               header.resize(2);
+               header[0] = (unsigned char)0x04;
+               header[1] = (unsigned char)(len & 0x7F);
+       }
+       else
+       {
+               // Count significate bytes
+               size_t bytes = sizeof(size_t);
+               for(; bytes > 0; bytes--)
+               {
+                       size_t value = len >> ((bytes - 1) * 8);
+                       if (value & 0xFF) break;
+               }
+
+               // Set header data
+               header.resize(2 + bytes);
+               header[0] = (unsigned char)0x04;
+               header[1] = (unsigned char)(0x80 | bytes);
+               for (size_t i = 1; i <= bytes; i++)
+               {
+                       header[2+bytes-i] = (unsigned char) (len & 0xFF);
+                       len >>= 8;
+               }
+       }
+
+       return header + pubData;
+}
+
+CK_RV SoftHSM::getGOSTPrivateKey(GOSTPrivateKey* privateKey, Token* token, OSObject* key)
+{
+       if (privateKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // GOST Private Key Attributes
+       ByteString value;
+       ByteString param;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_GOSTR3410_PARAMS), param);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               value = key->getByteStringValue(CKA_VALUE);
+               param = key->getByteStringValue(CKA_GOSTR3410_PARAMS);
+       }
+
+       privateKey->setD(value);
+       privateKey->setEC(param);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getGOSTPublicKey(GOSTPublicKey* publicKey, Token* token, OSObject* key)
+{
+       if (publicKey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       // GOST Public Key Attributes
+       ByteString point;
+       ByteString param;
+       if (isKeyPrivate)
+       {
+               bool bOK = true;
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), point);
+               bOK = bOK && token->decrypt(key->getByteStringValue(CKA_GOSTR3410_PARAMS), param);
+               if (!bOK)
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               point = key->getByteStringValue(CKA_VALUE);
+               param = key->getByteStringValue(CKA_GOSTR3410_PARAMS);
+       }
+
+       publicKey->setQ(point);
+       publicKey->setEC(param);
+
+       return CKR_OK;
+}
+
+CK_RV SoftHSM::getSymmetricKey(SymmetricKey* skey, Token* token, OSObject* key)
+{
+       if (skey == NULL) return CKR_ARGUMENTS_BAD;
+       if (token == NULL) return CKR_ARGUMENTS_BAD;
+       if (key == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Get the CKA_PRIVATE attribute, when the attribute is not present use default false
+       bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false);
+
+       ByteString keybits;
+       if (isKeyPrivate)
+       {
+               if (!token->decrypt(key->getByteStringValue(CKA_VALUE), keybits))
+                       return CKR_GENERAL_ERROR;
+       }
+       else
+       {
+               keybits = key->getByteStringValue(CKA_VALUE);
+       }
+
+       skey->setKeyBits(keybits);
+
+       return CKR_OK;
+}
+
+bool SoftHSM::setRSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const
+{
+       AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+       if (rsa == NULL)
+               return false;
+       PrivateKey* priv = rsa->newPrivateKey();
+       if (priv == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+               return false;
+       }
+       if (!priv->PKCS8Decode(ber))
+       {
+               rsa->recyclePrivateKey(priv);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+               return false;
+       }
+       // RSA Private Key Attributes
+       ByteString modulus;
+       ByteString publicExponent;
+       ByteString privateExponent;
+       ByteString prime1;
+       ByteString prime2;
+       ByteString exponent1;
+       ByteString exponent2;
+       ByteString coefficient;
+       if (isPrivate)
+       {
+               token->encrypt(((RSAPrivateKey*)priv)->getN(), modulus);
+               token->encrypt(((RSAPrivateKey*)priv)->getE(), publicExponent);
+               token->encrypt(((RSAPrivateKey*)priv)->getD(), privateExponent);
+               token->encrypt(((RSAPrivateKey*)priv)->getP(), prime1);
+               token->encrypt(((RSAPrivateKey*)priv)->getQ(), prime2);
+               token->encrypt(((RSAPrivateKey*)priv)->getDP1(), exponent1);
+               token->encrypt(((RSAPrivateKey*)priv)->getDQ1(), exponent2);
+               token->encrypt(((RSAPrivateKey*)priv)->getPQ(), coefficient);
+       }
+       else
+       {
+               modulus = ((RSAPrivateKey*)priv)->getN();
+               publicExponent = ((RSAPrivateKey*)priv)->getE();
+               privateExponent = ((RSAPrivateKey*)priv)->getD();
+               prime1 = ((RSAPrivateKey*)priv)->getP();
+               prime2 = ((RSAPrivateKey*)priv)->getQ();
+               exponent1 =  ((RSAPrivateKey*)priv)->getDP1();
+               exponent2 = ((RSAPrivateKey*)priv)->getDQ1();
+               coefficient = ((RSAPrivateKey*)priv)->getPQ();
+       }
+       bool bOK = true;
+       bOK = bOK && key->setAttribute(CKA_MODULUS, modulus);
+       bOK = bOK && key->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent);
+       bOK = bOK && key->setAttribute(CKA_PRIVATE_EXPONENT, privateExponent);
+       bOK = bOK && key->setAttribute(CKA_PRIME_1, prime1);
+       bOK = bOK && key->setAttribute(CKA_PRIME_2, prime2);
+       bOK = bOK && key->setAttribute(CKA_EXPONENT_1,exponent1);
+       bOK = bOK && key->setAttribute(CKA_EXPONENT_2, exponent2);
+       bOK = bOK && key->setAttribute(CKA_COEFFICIENT, coefficient);
+
+       rsa->recyclePrivateKey(priv);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+
+       return bOK;
+}
+
+bool SoftHSM::setDSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const
+{
+       AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+       if (dsa == NULL)
+               return false;
+       PrivateKey* priv = dsa->newPrivateKey();
+       if (priv == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+               return false;
+       }
+       if (!priv->PKCS8Decode(ber))
+       {
+               dsa->recyclePrivateKey(priv);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+               return false;
+       }
+       // DSA Private Key Attributes
+       ByteString prime;
+       ByteString subprime;
+       ByteString generator;
+       ByteString value;
+       if (isPrivate)
+       {
+               token->encrypt(((DSAPrivateKey*)priv)->getP(), prime);
+               token->encrypt(((DSAPrivateKey*)priv)->getQ(), subprime);
+               token->encrypt(((DSAPrivateKey*)priv)->getG(), generator);
+               token->encrypt(((DSAPrivateKey*)priv)->getX(), value);
+       }
+       else
+       {
+               prime = ((DSAPrivateKey*)priv)->getP();
+               subprime = ((DSAPrivateKey*)priv)->getQ();
+               generator = ((DSAPrivateKey*)priv)->getG();
+               value = ((DSAPrivateKey*)priv)->getX();
+       }
+       bool bOK = true;
+       bOK = bOK && key->setAttribute(CKA_PRIME, prime);
+       bOK = bOK && key->setAttribute(CKA_SUBPRIME, subprime);
+       bOK = bOK && key->setAttribute(CKA_BASE, generator);
+       bOK = bOK && key->setAttribute(CKA_VALUE, value);
+
+       dsa->recyclePrivateKey(priv);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+
+       return bOK;
+}
+
+bool SoftHSM::setDHPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const
+{
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh == NULL)
+               return false;
+       PrivateKey* priv = dh->newPrivateKey();
+       if (priv == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return false;
+       }
+       if (!priv->PKCS8Decode(ber))
+       {
+               dh->recyclePrivateKey(priv);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return false;
+       }
+       // DH Private Key Attributes
+       ByteString prime;
+       ByteString generator;
+       ByteString value;
+       if (isPrivate)
+       {
+               token->encrypt(((DHPrivateKey*)priv)->getP(), prime);
+               token->encrypt(((DHPrivateKey*)priv)->getG(), generator);
+               token->encrypt(((DHPrivateKey*)priv)->getX(), value);
+       }
+       else
+       {
+               prime = ((DHPrivateKey*)priv)->getP();
+               generator = ((DHPrivateKey*)priv)->getG();
+               value = ((DHPrivateKey*)priv)->getX();
+       }
+       bool bOK = true;
+       bOK = bOK && key->setAttribute(CKA_PRIME, prime);
+       bOK = bOK && key->setAttribute(CKA_BASE, generator);
+       bOK = bOK && key->setAttribute(CKA_VALUE, value);
+
+       dh->recyclePrivateKey(priv);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+       return bOK;
+}
+bool SoftHSM::setECPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const
+{
+       AsymmetricAlgorithm* ecc = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+       if (ecc == NULL)
+               return false;
+       PrivateKey* priv = ecc->newPrivateKey();
+       if (priv == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc);
+               return false;
+       }
+       if (!priv->PKCS8Decode(ber))
+       {
+               ecc->recyclePrivateKey(priv);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc);
+               return false;
+       }
+       // EC Private Key Attributes
+       ByteString group;
+       ByteString value;
+       if (isPrivate)
+       {
+               token->encrypt(((ECPrivateKey*)priv)->getEC(), group);
+               token->encrypt(((ECPrivateKey*)priv)->getD(), value);
+       }
+       else
+       {
+               group = ((ECPrivateKey*)priv)->getEC();
+               value = ((ECPrivateKey*)priv)->getD();
+       }
+       bool bOK = true;
+       bOK = bOK && key->setAttribute(CKA_EC_PARAMS, group);
+       bOK = bOK && key->setAttribute(CKA_VALUE, value);
+
+       ecc->recyclePrivateKey(priv);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc);
+
+       return bOK;
+}
+
+CK_RV SoftHSM::MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism)
+{
+       // This is a programming error
+       if (pMechanism->mechanism != CKM_RSA_PKCS_OAEP) {
+               ERROR_MSG("MechParamCheckRSAPKCSOAEP called on wrong mechanism");
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (pMechanism->pParameter == NULL_PTR ||
+           pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS))
+       {
+               ERROR_MSG("pParameter must be of type CK_RSA_PKCS_OAEP_PARAMS");
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       CK_RSA_PKCS_OAEP_PARAMS_PTR params = (CK_RSA_PKCS_OAEP_PARAMS_PTR)pMechanism->pParameter;
+       if (params->hashAlg != CKM_SHA_1)
+       {
+               ERROR_MSG("hashAlg must be CKM_SHA_1");
+               return CKR_ARGUMENTS_BAD;
+       }
+       if (params->mgf != CKG_MGF1_SHA1)
+       {
+               ERROR_MSG("mgf must be CKG_MGF1_SHA1");
+               return CKR_ARGUMENTS_BAD;
+       }
+       if (params->source != CKZ_DATA_SPECIFIED)
+       {
+               ERROR_MSG("source must be CKZ_DATA_SPECIFIED");
+               return CKR_ARGUMENTS_BAD;
+       }
+       if (params->pSourceData != NULL)
+       {
+               ERROR_MSG("pSourceData must be NULL");
+               return CKR_ARGUMENTS_BAD;
+       }
+       if (params->ulSourceDataLen != 0)
+       {
+               ERROR_MSG("ulSourceDataLen must be 0");
+               return CKR_ARGUMENTS_BAD;
+       }
+       return CKR_OK;
+}
+
+bool SoftHSM::isMechanismPermitted(OSObject* key, CK_MECHANISM_PTR pMechanism) {
+       OSAttribute attribute = key->getAttribute(CKA_ALLOWED_MECHANISMS);
+       std::set<CK_MECHANISM_TYPE> allowed = attribute.getMechanismTypeSetValue();
+       if (allowed.empty()) {
+               return true;
+       }
+
+       return allowed.find(pMechanism->mechanism) != allowed.end();
+}
diff --git a/SoftHSMv2/src/lib/SoftHSM.h b/SoftHSMv2/src/lib/SoftHSM.h
new file mode 100644 (file)
index 0000000..19909e4
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SoftHSM.h
+
+ This is the main class of the SoftHSM; it has the PKCS #11 interface and
+ dispatches all calls to the relevant components of the SoftHSM. The SoftHSM
+ class is a singleton implementation.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "cryptoki.h"
+#include "SessionObjectStore.h"
+#include "ObjectStore.h"
+#include "SessionManager.h"
+#include "SlotManager.h"
+#include "HandleManager.h"
+#include "RSAPublicKey.h"
+#include "RSAPrivateKey.h"
+#include "DSAPublicKey.h"
+#include "DSAPrivateKey.h"
+#include "ECPublicKey.h"
+#include "ECPrivateKey.h"
+#include "DHPublicKey.h"
+#include "DHPrivateKey.h"
+#include "GOSTPublicKey.h"
+#include "GOSTPrivateKey.h"
+
+#include <memory>
+
+class SoftHSM
+{
+public:
+       // Return the one-and-only instance
+       static SoftHSM* i();
+
+       // This will destroy the one-and-only instance.
+       static void reset();
+
+       // Destructor
+       virtual ~SoftHSM();
+
+       // PKCS #11 functions
+       CK_RV C_Initialize(CK_VOID_PTR pInitArgs);
+       CK_RV C_Finalize(CK_VOID_PTR pReserved);
+       CK_RV C_GetInfo(CK_INFO_PTR pInfo);
+       CK_RV C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount);
+       CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo);
+       CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo);
+       CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount);
+       CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo);
+       CK_RV C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel);
+       CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen);
+       CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen);
+       CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession);
+       CK_RV C_CloseSession(CK_SESSION_HANDLE hSession);
+       CK_RV C_CloseAllSessions(CK_SLOT_ID slotID);
+       CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo);
+       CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen);
+       CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey);
+       CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen);
+       CK_RV C_Logout(CK_SESSION_HANDLE hSession);
+       CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject);
+       CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject);
+       CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject);
+       CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize);
+       CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
+       CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
+       CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
+       CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount);
+       CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession);
+       CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen);
+       CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen);
+       CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen);
+       CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen);
+       CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen);
+       CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen);
+       CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism);
+       CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen);
+       CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen);
+       CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject);
+       CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen);
+       CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen);
+       CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen);
+       CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen);
+       CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen);
+       CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen);
+       CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen);
+       CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen);
+       CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen);
+       CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen);
+       CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pDecryptedPart, CK_ULONG_PTR pulDecryptedPartLen);
+       CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen);
+       CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen);
+       CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey);
+       CK_RV C_GenerateKeyPair
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey
+       );
+       CK_RV C_WrapKey
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hWrappingKey,
+               CK_OBJECT_HANDLE hKey,
+               CK_BYTE_PTR pWrappedKey,
+               CK_ULONG_PTR pulWrappedKeyLen
+       );
+       CK_RV C_UnwrapKey
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hUnwrappingKey,
+               CK_BYTE_PTR pWrappedKey,
+               CK_ULONG ulWrappedKeyLen,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR hKey
+       );
+       CK_RV C_DeriveKey
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hBaseKey,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey
+       );
+       CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen);
+       CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen);
+       CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession);
+       CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession);
+       CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved);
+
+private:
+       // Constructor
+       SoftHSM();
+
+       // The one-and-only instance
+#ifdef HAVE_CXX11
+       static std::unique_ptr<SoftHSM> instance;
+#else
+       static std::auto_ptr<SoftHSM> instance;
+#endif
+
+       // Is the SoftHSM PKCS #11 library initialised?
+       bool isInitialised;
+       bool isRemovable;
+
+       SessionObjectStore* sessionObjectStore;
+       ObjectStore* objectStore;
+       SlotManager* slotManager;
+       SessionManager* sessionManager;
+       HandleManager* handleManager;
+
+       // Encrypt/Decrypt variants
+       CK_RV SymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV AsymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV SymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV AsymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+
+       // Sign/Verify variants
+       CK_RV MacSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV MacVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+       CK_RV AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey);
+
+       // Key generation
+       CK_RV generateDES
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateDES2
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateDES3
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateAES
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateRSA
+       (CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey,
+               CK_BBOOL isPublicKeyOnToken,
+               CK_BBOOL isPublicKeyPrivate,
+               CK_BBOOL isPrivateKeyOnToken,
+               CK_BBOOL isPrivateKeyPrivate
+       );
+       CK_RV generateDSA
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey,
+               CK_BBOOL isPublicKeyOnToken,
+               CK_BBOOL isPublicKeyPrivate,
+               CK_BBOOL isPrivateKeyOnToken,
+               CK_BBOOL isPrivateKeyPrivate
+       );
+       CK_RV generateDSAParameters
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateEC
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey,
+               CK_BBOOL isPublicKeyOnToken,
+               CK_BBOOL isPublicKeyPrivate,
+               CK_BBOOL isPrivateKeyOnToken,
+               CK_BBOOL isPrivateKeyPrivate
+       );
+       CK_RV generateDH
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey,
+               CK_BBOOL isPublicKeyOnToken,
+               CK_BBOOL isPublicKeyPrivate,
+               CK_BBOOL isPrivateKeyOnToken,
+               CK_BBOOL isPrivateKeyPrivate
+       );
+       CK_RV generateDHParameters
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV generateGOST
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+               CK_ULONG ulPublicKeyAttributeCount,
+               CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+               CK_ULONG ulPrivateKeyAttributeCount,
+               CK_OBJECT_HANDLE_PTR phPublicKey,
+               CK_OBJECT_HANDLE_PTR phPrivateKey,
+               CK_BBOOL isPublicKeyOnToken,
+               CK_BBOOL isPublicKeyPrivate,
+               CK_BBOOL isPrivateKeyOnToken,
+               CK_BBOOL isPrivateKeyPrivate
+       );
+       CK_RV deriveDH
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hBaseKey,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_KEY_TYPE keyType,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV deriveECDH
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hBaseKey,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_KEY_TYPE keyType,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV deriveSymmetric
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_MECHANISM_PTR pMechanism,
+               CK_OBJECT_HANDLE hBaseKey,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phKey,
+               CK_KEY_TYPE keyType,
+               CK_BBOOL isOnToken,
+               CK_BBOOL isPrivate
+       );
+       CK_RV CreateObject
+       (
+               CK_SESSION_HANDLE hSession,
+               CK_ATTRIBUTE_PTR pTemplate,
+               CK_ULONG ulCount,
+               CK_OBJECT_HANDLE_PTR phObject,
+               int op
+       );
+
+       CK_RV getRSAPrivateKey(RSAPrivateKey* privateKey, Token* token, OSObject* key);
+       CK_RV getRSAPublicKey(RSAPublicKey* publicKey, Token* token, OSObject* key);
+       CK_RV getDSAPrivateKey(DSAPrivateKey* privateKey, Token* token, OSObject* key);
+       CK_RV getDSAPublicKey(DSAPublicKey* publicKey, Token* token, OSObject* key);
+       CK_RV getECPrivateKey(ECPrivateKey* privateKey, Token* token, OSObject* key);
+       CK_RV getECPublicKey(ECPublicKey* publicKey, Token* token, OSObject* key);
+       CK_RV getDHPrivateKey(DHPrivateKey* privateKey, Token* token, OSObject* key);
+       CK_RV getDHPublicKey(DHPublicKey* publicKey, DHPrivateKey* privateKey, ByteString& pubParams);
+       CK_RV getECDHPublicKey(ECPublicKey* publicKey, ECPrivateKey* privateKey, ByteString& pubData);
+       CK_RV getGOSTPrivateKey(GOSTPrivateKey* privateKey, Token* token, OSObject* key);
+       CK_RV getGOSTPublicKey(GOSTPublicKey* publicKey, Token* token, OSObject* key);
+       CK_RV getSymmetricKey(SymmetricKey* skey, Token* token, OSObject* key);
+
+       ByteString getECDHPubData(ByteString& pubData);
+
+       bool setRSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const;
+       bool setDSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const;
+       bool setDHPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const;
+       bool setECPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const;
+
+
+       CK_RV WrapKeyAsym
+       (
+               CK_MECHANISM_PTR pMechanism,
+               Token *token,
+               OSObject *wrapKey,
+               ByteString &keydata,
+               ByteString &wrapped
+       );
+
+       CK_RV WrapKeySym
+       (
+               CK_MECHANISM_PTR pMechanism,
+               Token *token,
+               OSObject *wrapKey,
+               ByteString &keydata,
+               ByteString &wrapped
+       );
+
+       CK_RV UnwrapKeyAsym
+       (
+               CK_MECHANISM_PTR pMechanism,
+               ByteString &wrapped,
+               Token* token,
+               OSObject *unwrapKey,
+               ByteString &keydata
+       );
+
+       CK_RV UnwrapKeySym
+       (
+               CK_MECHANISM_PTR pMechanism,
+               ByteString &wrapped,
+               Token* token,
+               OSObject *unwrapKey,
+               ByteString &keydata
+       );
+
+       CK_RV MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism);
+
+       static bool isMechanismPermitted(OSObject* key, CK_MECHANISM_PTR pMechanism);
+};
+
diff --git a/SoftHSMv2/src/lib/access.cpp b/SoftHSMv2/src/lib/access.cpp
new file mode 100644 (file)
index 0000000..66473d1
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ access.cpp
+
+ Implements the access rules.
+ *****************************************************************************/
+
+#include "access.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+// Checks if a read operation is allowed on a given object type.
+//
+//                                             Type of session
+//  Type of object          R/O Public | R/W Public | R/O User | R/W User | R/W SO
+//  ------------------------------------------------------------------------------
+//  Public session object       OK     |     OK     |    OK    |    OK    |   OK
+//  Private session object      UNLI   |     UNLI   |    OK    |    OK    |   UNLI
+//  Public token object         OK     |     OK     |    OK    |    OK    |   OK
+//  Private token object        UNLI   |     UNLI   |    OK    |    OK    |   UNLI
+//
+// OK = CKR_OK
+// SRO = CKR_SESSION_READ_ONLY
+// UNLI = CKR_USER_NOT_LOGGED_IN
+
+// Can we do read operations?
+CK_RV haveRead(CK_STATE sessionState, CK_BBOOL /*isTokenObject*/, CK_BBOOL isPrivateObject)
+{
+       switch (sessionState)
+       {
+        case CKS_RO_PUBLIC_SESSION:
+        case CKS_RW_PUBLIC_SESSION:
+        case CKS_RW_SO_FUNCTIONS:
+            return isPrivateObject ? CKR_USER_NOT_LOGGED_IN : CKR_OK;
+        case CKS_RO_USER_FUNCTIONS:
+        case CKS_RW_USER_FUNCTIONS:
+            return CKR_OK;
+    }
+    return CKR_GENERAL_ERROR; // internal error, switch should have covered every state
+}
+
+// Checks if a write operation is allowed on a given object type.
+//
+//                                             Type of session
+//  Type of object          R/O Public | R/W Public | R/O User | R/W User | R/W SO
+//  ------------------------------------------------------------------------------
+//  Public session object       OK     |     OK     |    OK    |    OK    |   OK
+//  Private session object      UNLI   |     UNLI   |    OK    |    OK    |   UNLI
+//  Public token object         SRO    |     OK     |    SRO   |    OK    |   OK
+//  Private token object      SRO/UNLI |     UNLI   |    SRO   |    OK    |   UNLI
+//
+// OK = CKR_OK
+// SRO = CKR_SESSION_READ_ONLY
+// UNLI = CKR_USER_NOT_LOGGED_IN
+// In the situation where both SRO and UNLI may be returned we favor SRO.
+
+// Can we do write operations?
+CK_RV haveWrite(CK_STATE sessionState, CK_BBOOL isTokenObject, CK_BBOOL isPrivateObject)
+{
+       switch (sessionState)
+       {
+        case CKS_RO_PUBLIC_SESSION:
+            if (isTokenObject)
+                return CKR_SESSION_READ_ONLY;
+            else
+                return isPrivateObject ? CKR_USER_NOT_LOGGED_IN : CKR_OK;
+        case CKS_RW_PUBLIC_SESSION:
+        case CKS_RW_SO_FUNCTIONS:
+            return isPrivateObject ? CKR_USER_NOT_LOGGED_IN : CKR_OK;
+        case CKS_RO_USER_FUNCTIONS:
+            return isTokenObject ? CKR_SESSION_READ_ONLY : CKR_OK;
+        case CKS_RW_USER_FUNCTIONS:
+            return CKR_OK;
+       }
+    return CKR_GENERAL_ERROR; // internal error, switch should have covered every state
+}
diff --git a/SoftHSMv2/src/lib/access.h b/SoftHSMv2/src/lib/access.h
new file mode 100644 (file)
index 0000000..36f303f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ access.h
+
+ Implements the access rules.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ACCESS_H
+#define _SOFTHSM_V2_ACCESS_H
+
+#include "cryptoki.h"
+
+CK_RV haveRead(CK_STATE sessionState, CK_BBOOL isTokenObject, CK_BBOOL isPrivateObject);
+CK_RV haveWrite(CK_STATE sessionState, CK_BBOOL isTokenObject, CK_BBOOL isPrivateObject);
+
+#endif /* !_SOFTHSM_V2_ACCESS_H */
+
diff --git a/SoftHSMv2/src/lib/common/Configuration.cpp b/SoftHSMv2/src/lib/common/Configuration.cpp
new file mode 100644 (file)
index 0000000..a7f6cc6
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Configuration.cpp
+
+ Loads the configuration and supports retrieval of configuration information
+ *****************************************************************************/
+
+#include <string>
+#include <map>
+#include "Configuration.h"
+#include "log.h"
+
+// Initialise the one-and-only instance
+#ifdef HAVE_CXX11
+std::unique_ptr<Configuration> Configuration::instance(nullptr);
+#else
+std::auto_ptr<Configuration> Configuration::instance(NULL);
+#endif
+
+// Add all valid configurations
+const struct config Configuration::valid_config[] = {
+       { "directories.tokendir",       CONFIG_TYPE_STRING },
+       { "objectstore.backend",        CONFIG_TYPE_STRING },
+       { "log.level",                  CONFIG_TYPE_STRING },
+       { "slots.removable",            CONFIG_TYPE_BOOL },
+       { "",                           CONFIG_TYPE_UNSUPPORTED }
+};
+
+// Return the one-and-only instance
+Configuration* Configuration::i()
+{
+       if (instance.get() == NULL)
+       {
+               instance.reset(new Configuration());
+       }
+
+       return instance.get();
+}
+
+// Constructor
+Configuration::Configuration()
+{
+       configLoader = NULL;
+}
+
+// Get the type of the configuration value
+int Configuration::getType(std::string key)
+{
+       for (int i = 0; valid_config[i].key.compare("") != 0; i++)
+       {
+               if (valid_config[i].key.compare(key) == 0)
+               {
+                       return valid_config[i].type;
+               }
+       }
+
+       return CONFIG_TYPE_UNSUPPORTED;
+}
+
+// Retrieve a string based configuration value
+std::string Configuration::getString(std::string key, std::string ifEmpty /* = "" */)
+{
+       if (stringConfiguration.find(key) != stringConfiguration.end())
+       {
+               return stringConfiguration[key];
+       }
+       else
+       {
+               WARNING_MSG("Missing %s in configuration. Using default value: %s", key.c_str(), ifEmpty.c_str());
+               return ifEmpty;
+       }
+}
+
+// Retrieve an integer configuration value
+int Configuration::getInt(std::string key, int ifEmpty /* = 0 */)
+{
+       if (integerConfiguration.find(key) != integerConfiguration.end())
+       {
+               return integerConfiguration[key];
+       }
+       else
+       {
+               WARNING_MSG("Missing %s in configuration. Using default value: %i", key.c_str(), ifEmpty);
+               return ifEmpty;
+       }
+}
+
+// Retrieve a boolean configuration value
+bool Configuration::getBool(std::string key, bool ifEmpty /* = false */)
+{
+       if (booleanConfiguration.find(key) != booleanConfiguration.end())
+       {
+               return booleanConfiguration[key];
+       }
+       else
+       {
+               WARNING_MSG("Missing %s in configuration. Using default value: %s", key.c_str(), ifEmpty ? "true" : "false");
+               return ifEmpty;
+       }
+}
+
+// Set a string based configuration value
+void Configuration::setString(std::string key, std::string value)
+{
+       stringConfiguration[key] = value;
+}
+
+// Set an integer based configuration value
+void Configuration::setInt(std::string key, int value)
+{
+       integerConfiguration[key] = value;
+}
+
+// Set a boolean configuration value
+void Configuration::setBool(std::string key, bool value)
+{
+       booleanConfiguration[key] = value;
+}
+
+// Reload the configuration
+bool Configuration::reload()
+{
+       if (configLoader == NULL)
+       {
+               return false;
+       }
+
+       // Discard the current configuration
+       stringConfiguration.clear();
+       integerConfiguration.clear();
+       booleanConfiguration.clear();
+
+       // Reload the configuration
+       if (!configLoader->loadConfiguration())
+       {
+               ERROR_MSG("Failed to load the SoftHSM configuration");
+
+               return false;
+       }
+
+       return true;
+}
+
+// Reload the configuration using the specified configuration loader
+bool Configuration::reload(ConfigLoader* inConfigLoader)
+{
+       configLoader = inConfigLoader;
+
+       return reload();
+}
+
diff --git a/SoftHSMv2/src/lib/common/Configuration.h b/SoftHSMv2/src/lib/common/Configuration.h
new file mode 100644 (file)
index 0000000..eacb493
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Configuration.h
+
+ Loads the configuration and supports retrieval of configuration information
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_CONFIGURATION_H
+#define _SOFTHSM_V2_CONFIGURATION_H
+
+#include "config.h"
+#include <string>
+#include <map>
+#include <memory>
+
+enum
+{
+       CONFIG_TYPE_UNSUPPORTED,
+       CONFIG_TYPE_STRING,
+       CONFIG_TYPE_INT,
+       CONFIG_TYPE_BOOL
+};
+
+struct config
+{
+       std::string key;
+       int type;
+};
+
+class ConfigLoader
+{
+public:
+       virtual ~ConfigLoader() { }
+
+       // Trigger loading of the configuration
+       virtual bool loadConfiguration() = 0;
+};
+
+class Configuration
+{
+public:
+       static Configuration* i();
+
+       virtual ~Configuration() { }
+
+       // Get the type of the configuration value
+       int getType(std::string key);
+
+       // Retrieve a string based configuration value
+       std::string getString(std::string key, std::string ifEmpty = std::string(""));
+
+       // Retrieve an integer configuration value
+       int getInt(std::string key, int ifEmpty = 0);
+
+       // Retrieve a boolean configuration value
+       bool getBool(std::string key, bool ifEmpty = false);
+
+       // Set a string based configuration value
+       void setString(std::string key, std::string value);
+
+       // Set an integer based configuration value
+       void setInt(std::string key, int value);
+
+       // Set a boolean configuration value
+       void setBool(std::string key, bool value);
+
+       // Reload the configuration
+       bool reload();
+
+       // Reload the configuration using the specified configuration loader
+       bool reload(ConfigLoader* inConfigLoader);
+
+private:
+       Configuration();
+
+#ifdef HAVE_CXX11
+       static std::unique_ptr<Configuration> instance;
+#else
+       static std::auto_ptr<Configuration> instance;
+#endif
+
+       std::map<std::string, std::string> stringConfiguration;
+       std::map<std::string, int> integerConfiguration;
+       std::map<std::string, bool> booleanConfiguration;
+
+       ConfigLoader* configLoader;
+
+       static const struct config valid_config[];
+};
+
+#endif // !_SOFTHSM_V2_CONFIGURATION_H
+
diff --git a/SoftHSMv2/src/lib/common/HandleFactory.h b/SoftHSMv2/src/lib/common/HandleFactory.h
new file mode 100644 (file)
index 0000000..0b9dc1f
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ HandleFactory.h
+
+ This is a template class for handling handles ;-)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HANDLEFACTORY_H
+#define _SOFTHSM_V2_HANDLEFACTORY_H
+
+#include "config.h"
+#include "log.h"
+#include "MutexFactory.h"
+#include <map>
+#include <queue>
+
+template <class hType, class oType> class HandleFactory
+{
+public:
+       // Constructor
+       HandleFactory() 
+       {
+               nextFree = (hType) 1;
+               handleMutex = MutexFactory::i()->getMutex();
+       }
+
+       // Destructor
+       virtual ~HandleFactory() 
+       {
+               MutexFactory::i()->recycleMutex(handleMutex);
+       }
+
+       // Get a new handle for the specified object
+       hType getHandle(oType object)
+       {
+               MutexLocker lock(handleMutex);
+
+               hType handle;
+
+               if (!recycledHandles.empty())
+               {
+                       handle = recycledHandles.front();
+                       recycledHandles.pop();
+               }
+               else
+               {
+                       handle = nextFree++;
+               }
+
+               handleMap[handle] = object;
+
+               return handle;
+       }
+
+       // Check whether the specified handle is valid
+       bool isValid(hType handle)
+       {
+               MutexLocker lock(handleMutex);
+
+               return (handleMap.find(handle) != handleMap.end());
+       }
+
+       // Return the object for the specified handle
+       oType getObjectByHandle(hType handle)
+       {
+               MutexLocker lock(handleMutex);
+
+               return handleMap[handle];
+       }
+
+       // Discard the specified handle
+       void deleteHandle(hType handle)
+       {
+               MutexLocker lock(handleMutex);
+
+               handleMap.erase(handle);
+
+               recycledHandles.push(handle);
+       }
+
+private:
+       // The handle map
+       std::map<hType, oType> handleMap;
+
+       // The set of recycled handles
+       std::queue<hType> recycledHandles;
+
+       // The next free handle
+       hType nextFree;
+
+       // Cross-thread synchronisation
+       Mutex* handleMutex;
+};
+
+#endif // !_SOFTHSM_V2_HANDLEFACTORY_H
+
diff --git a/SoftHSMv2/src/lib/common/Makefile.am b/SoftHSMv2/src/lib/common/Makefile.am
new file mode 100644 (file)
index 0000000..bf18b1a
--- /dev/null
@@ -0,0 +1,28 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../crypto \
+                               -I$(srcdir)/../data_mgr \
+                               -I$(srcdir)/../pkcs11
+
+noinst_LTLIBRARIES =           libsofthsm_common.la
+libsofthsm_common_la_SOURCES = Configuration.cpp \
+                               fatal.cpp \
+                               log.cpp \
+                               osmutex.cpp \
+                               SimpleConfigLoader.cpp \
+                               MutexFactory.cpp
+
+man_MANS =                     softhsm2.conf.5
+
+EXTRA_DIST =                   $(srcdir)/*.h \
+                               $(srcdir)/softhsm2.conf.5.in
+
+install-data-hook:
+       test -d ${DESTDIR}${sysconfdir} || \
+               ${INSTALL} -d ${DESTDIR}${sysconfdir}
+       test -f ${DESTDIR}${sysconfdir}/softhsm2.conf || \
+               ${INSTALL_DATA} ${top_builddir}/src/lib/common/softhsm2.conf ${DESTDIR}${sysconfdir}
+       ${INSTALL_DATA} ${top_builddir}/src/lib/common/softhsm2.conf ${DESTDIR}${sysconfdir}/softhsm2.conf.sample
+       test -d ${DESTDIR}${softhsmtokendir} || \
+               ${INSTALL} -d -m 1777 ${DESTDIR}${softhsmtokendir}
diff --git a/SoftHSMv2/src/lib/common/MutexFactory.cpp b/SoftHSMv2/src/lib/common/MutexFactory.cpp
new file mode 100644 (file)
index 0000000..1cfc0da
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MutexFactory.cpp
+
+ This factory produces OS specific mutex objects
+ *****************************************************************************/
+
+#include "config.h"
+#include "MutexFactory.h"
+#include "osmutex.h"
+#include <memory>
+#include <stddef.h>
+
+/*****************************************************************************
+ Mutex implementation
+ *****************************************************************************/
+
+// Constructor
+Mutex::Mutex()
+{
+       isValid = (MutexFactory::i()->CreateMutex(&handle) == CKR_OK);
+}
+
+// Destructor
+Mutex::~Mutex()
+{
+       if (isValid)
+       {
+               MutexFactory::i()->DestroyMutex(handle);
+       }
+}
+
+// Lock the mutex
+bool Mutex::lock()
+{
+       return (isValid && (MutexFactory::i()->LockMutex(handle) == CKR_OK));
+}
+
+// Unlock the mutex
+void Mutex::unlock()
+{
+       if (isValid)
+       {
+               MutexFactory::i()->UnlockMutex(handle);
+       }
+}
+
+/*****************************************************************************
+ MutexLocker implementation
+ *****************************************************************************/
+
+// Constructor
+MutexLocker::MutexLocker(Mutex* inMutex)
+{
+       mutex = inMutex;
+
+       if (mutex != NULL) mutex->lock();
+}
+
+// Destructor
+MutexLocker::~MutexLocker()
+{
+       if (mutex != NULL) mutex->unlock();
+}
+
+/*****************************************************************************
+ MutexFactory implementation
+ *****************************************************************************/
+
+// Constructor
+MutexFactory::MutexFactory()
+{
+       createMutex = OSCreateMutex;
+       destroyMutex = OSDestroyMutex;
+       lockMutex = OSLockMutex;
+       unlockMutex = OSUnlockMutex;
+
+       enabled = true;
+}
+
+// Destructor
+MutexFactory::~MutexFactory()
+{
+}
+
+// Return the one-and-only instance
+MutexFactory* MutexFactory::i()
+{
+       if (!instance.get())
+       {
+               instance.reset(new MutexFactory());
+       }
+
+       return instance.get();
+}
+
+// Get a mutex instance
+Mutex* MutexFactory::getMutex()
+{
+       return new Mutex();
+}
+
+// Recycle a mutex instance
+void MutexFactory::recycleMutex(Mutex* mutex)
+{
+       if (mutex != NULL) delete mutex;
+}
+
+// Set the function pointers
+void MutexFactory::setCreateMutex(CK_CREATEMUTEX inCreateMutex)
+{
+       createMutex = inCreateMutex;
+}
+
+void MutexFactory::setDestroyMutex(CK_DESTROYMUTEX inDestroyMutex)
+{
+       destroyMutex = inDestroyMutex;
+}
+
+void MutexFactory::setLockMutex(CK_LOCKMUTEX inLockMutex)
+{
+       lockMutex = inLockMutex;
+}
+
+void MutexFactory::setUnlockMutex(CK_UNLOCKMUTEX inUnlockMutex)
+{
+       unlockMutex = inUnlockMutex;
+}
+
+void MutexFactory::enable()
+{
+       enabled = true;
+}
+
+void MutexFactory::disable()
+{
+       enabled = false;
+}
+
+CK_RV MutexFactory::CreateMutex(CK_VOID_PTR_PTR newMutex)
+{
+       if (!enabled) return CKR_OK;
+
+       return (this->createMutex)(newMutex);
+}
+
+CK_RV MutexFactory::DestroyMutex(CK_VOID_PTR mutex)
+{
+       if (!enabled) return CKR_OK;
+
+       return (this->destroyMutex)(mutex);
+}
+
+CK_RV MutexFactory::LockMutex(CK_VOID_PTR mutex)
+{
+       if (!enabled) return CKR_OK;
+
+       return (this->lockMutex)(mutex);
+}
+
+CK_RV MutexFactory::UnlockMutex(CK_VOID_PTR mutex)
+{
+       if (!enabled) return CKR_OK;
+
+       return (this->unlockMutex)(mutex);
+}
+
diff --git a/SoftHSMv2/src/lib/common/MutexFactory.h b/SoftHSMv2/src/lib/common/MutexFactory.h
new file mode 100644 (file)
index 0000000..167dc3d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MutexFactory.h
+
+ This factory produces OS specific mutex objects
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_MUTEXFACTORY_H
+#define _SOFTHSM_V2_MUTEXFACTORY_H
+
+#include "config.h"
+#include "osmutex.h"
+#include "cryptoki.h"
+#include <memory>
+
+class Mutex
+{
+public:
+       // Constructor
+       Mutex();
+
+       // Destructor
+       virtual ~Mutex();
+
+       // Lock the mutex
+       bool lock();
+
+       // Unlock the mutex
+       void unlock();
+
+private:
+       // The mutex handle
+       CK_VOID_PTR handle;
+
+       // Is the mutex valid?
+       bool isValid;
+};
+
+class MutexLocker
+{
+public:
+       // Constructor
+       MutexLocker(Mutex* inMutex);
+
+       // Destructor
+       virtual ~MutexLocker();
+
+private:
+       // The mutex to lock
+       Mutex* mutex;
+};
+
+class MutexFactory
+{
+public:
+       // Return the one-and-only instance
+       static MutexFactory* i();
+
+       // Destructor
+       virtual ~MutexFactory();
+
+       // Get a mutex instance
+       Mutex* getMutex();
+
+       // Recycle a mutex instance
+       void recycleMutex(Mutex* mutex);
+
+       // Set the function pointers
+       void setCreateMutex(CK_CREATEMUTEX inCreateMutex);
+       void setDestroyMutex(CK_DESTROYMUTEX inDestroyMutex);
+       void setLockMutex(CK_LOCKMUTEX inLockMutex);
+       void setUnlockMutex(CK_UNLOCKMUTEX inUnlockMutex);
+
+       // Enable/disable mutex handling
+       void enable();
+       void disable();
+
+private:
+       // Constructor
+       MutexFactory();
+
+       // Mutex operations
+       friend class Mutex;
+
+       CK_RV CreateMutex(CK_VOID_PTR_PTR newMutex);
+       CK_RV DestroyMutex(CK_VOID_PTR mutex);
+       CK_RV LockMutex(CK_VOID_PTR mutex);
+       CK_RV UnlockMutex(CK_VOID_PTR mutex);
+
+       // The one-and-only instance
+#ifdef HAVE_CXX11
+       static std::unique_ptr<MutexFactory> instance;
+#else
+       static std::auto_ptr<MutexFactory> instance;
+#endif
+
+       // The function pointers
+       CK_CREATEMUTEX createMutex;
+       CK_DESTROYMUTEX destroyMutex;
+       CK_LOCKMUTEX lockMutex;
+       CK_UNLOCKMUTEX unlockMutex;
+
+       // Can we do mutex handling?
+       bool enabled;
+};
+
+#endif // !_SOFTHSM_V2_MUTEXFACTORY_H
+
diff --git a/SoftHSMv2/src/lib/common/Serialisable.h b/SoftHSMv2/src/lib/common/Serialisable.h
new file mode 100644 (file)
index 0000000..819940e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Serialisable.h
+
+ Interface description for serialisable classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SERIALISABLE_H
+#define _SOFTHSM_V2_SERIALISABLE_H
+
+#include "config.h"
+#include "ByteString.h"
+
+class ByteString;
+
+class Serialisable
+{
+public:
+       // Serialise the data content of a class
+       virtual ByteString serialise() const = 0;
+
+       // Default destructor
+       virtual ~Serialisable() { }
+};
+
+#endif // !_SOFTHSM_V2_SERIALISABLE_H
+
diff --git a/SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp b/SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp
new file mode 100644 (file)
index 0000000..3212d82
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2010 .SE, The Internet Infrastructure Foundation
+ * 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.
+ */
+
+/*****************************************************************************
+ SimpleConfigLoader.cpp
+
+ Loads the configuration from the configuration file.
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <limits.h>
+#ifdef _WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#include "config.h"
+#if defined(HAVE_GETPWUID_R)
+# include <sys/types.h>
+# include <pwd.h>
+#endif
+#include "SimpleConfigLoader.h"
+#include "log.h"
+#include "Configuration.h"
+
+// Initialise the one-and-only instance
+#ifdef HAVE_CXX11
+std::unique_ptr<SimpleConfigLoader> SimpleConfigLoader::instance(nullptr);
+#else
+std::auto_ptr<SimpleConfigLoader> SimpleConfigLoader::instance(NULL);
+#endif
+
+// Return the one-and-only instance
+SimpleConfigLoader* SimpleConfigLoader::i()
+{
+       if (instance.get() == NULL)
+       {
+               instance.reset(new SimpleConfigLoader());
+       }
+
+       return instance.get();
+}
+
+// Constructor
+SimpleConfigLoader::SimpleConfigLoader()
+{
+}
+
+// Load the configuration
+bool SimpleConfigLoader::loadConfiguration()
+{
+       char* configPath = getConfigPath();
+
+       FILE* fp = fopen(configPath,"r");
+
+       if (fp == NULL)
+       {
+               ERROR_MSG("Could not open the config file: %s", configPath);
+               free(configPath);
+               return false;
+       }
+       free(configPath);
+
+       char fileBuf[1024];
+
+       // Format in config file
+       //
+       // <name> = <value>
+       // # Line is ignored
+
+       size_t line = 0;
+       while (fgets(fileBuf, sizeof(fileBuf), fp) != NULL)
+       {
+               line++;
+
+               // End the string at the first comment or newline
+               fileBuf[strcspn(fileBuf, "#\n\r")] = '\0';
+
+               // Skip empty lines
+               if (fileBuf[0] == '\0')
+               {
+                       continue;
+               }
+
+               // Get the first part of the line
+               char* name = strtok(fileBuf, "=");
+               if (name == NULL)
+               {
+                       WARNING_MSG("Bad format on line %lu, skip", (unsigned long)line);
+                       continue;
+               }
+
+               // Trim the name
+               char* trimmedName = trimString(name);
+               if (trimmedName == NULL)
+               {
+                       WARNING_MSG("Bad format on line %lu, skip", (unsigned long)line);
+                       continue;
+               }
+
+               // Get the second part of the line
+               char* value = strtok(NULL, "=");
+               if(value == NULL) {
+                       WARNING_MSG("Bad format on line %lu, skip", (unsigned long)line);
+                       free(trimmedName);
+                       continue;
+               }
+
+               // Trim the value
+               char* trimmedValue = trimString(value);
+               if (trimmedValue == NULL)
+               {
+                       WARNING_MSG("Bad format on line %lu, skip", (unsigned long)line);
+                       free(trimmedName);
+                       continue;
+               }
+
+               // Save name,value
+               std::string stringName(trimmedName);
+               std::string stringValue(trimmedValue);
+               free(trimmedName);
+               free(trimmedValue);
+
+               switch (Configuration::i()->getType(stringName))
+               {
+                       case CONFIG_TYPE_STRING:
+                               Configuration::i()->setString(stringName, stringValue);
+                               break;
+                       case CONFIG_TYPE_INT:
+                               Configuration::i()->setInt(stringName, atoi(stringValue.c_str()));
+                               break;
+                       case CONFIG_TYPE_BOOL:
+                               bool boolValue;
+                               if (string2bool(stringValue, &boolValue))
+                               {
+                                       Configuration::i()->setBool(stringName, boolValue);
+                               }
+                               else
+                               {
+                                       WARNING_MSG("The value %s is not a boolean", stringValue.c_str());
+                               }
+                               break;
+                       case CONFIG_TYPE_UNSUPPORTED:
+                       default:
+                               WARNING_MSG("The following configuration is not supported: %s = %s",
+                                       stringName.c_str(), stringValue.c_str());
+                               break;
+               }
+       }
+
+       fclose(fp);
+
+       return true;
+}
+
+// Get the boolean value from a string
+bool SimpleConfigLoader::string2bool(std::string stringValue, bool* boolValue)
+{
+       // Convert to lowercase
+       std::transform(stringValue.begin(), stringValue.end(), stringValue.begin(), tolower);
+
+       if (stringValue.compare("true") == 0)
+       {
+               *boolValue = true;
+               return true;
+       }
+
+       if (stringValue.compare("false") == 0)
+       {
+               *boolValue = false;
+               return true;
+       }
+
+       return false;
+}
+
+#define CONFIG_FILE ".config/softhsm2/softhsm2.conf"
+
+/* Returns a user-specific path for configuration.
+ */
+static char *get_user_path(void)
+{
+#ifdef _WIN32
+       char path[512];
+       const char *home_drive = getenv("HOMEDRIVE");
+       const char *home_path = getenv("HOMEPATH");
+
+       if (home_drive && home_path) {
+               snprintf(path, sizeof(path), "%s%s\\softhsm2.conf", home_drive, home_path);
+
+               if (_access(path, 0) == 0)
+                       return strdup(path);
+       }
+       goto fail;
+#else
+       char path[_POSIX_PATH_MAX];
+       const char *home_dir = getenv("HOME");
+
+       if (home_dir != NULL && home_dir[0] != 0) {
+               snprintf(path, sizeof(path), "%s/" CONFIG_FILE, home_dir);
+               if (access(path, R_OK) == 0)
+                       return strdup(path);
+               else
+                       goto fail;
+       }
+
+# if defined(HAVE_GETPWUID_R)
+       if (home_dir == NULL || home_dir[0] == '\0') {
+               struct passwd *pwd;
+               struct passwd _pwd;
+               int ret;
+               char tmp[512];
+
+               ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd);
+               if (ret == 0 && pwd != NULL) {
+                       snprintf(path, sizeof(path), "%s/" CONFIG_FILE, pwd->pw_dir);
+                       if (access(path, R_OK) == 0)
+                               return strdup(path);
+                       else
+                               goto fail;
+               }
+       }
+# endif
+#endif
+
+ fail:
+       return NULL;
+}
+
+static char *get_env_var_path(void)
+{
+#ifdef _WIN32
+
+       LPSTR value = NULL;
+       DWORD size = 0;
+
+       size = GetEnvironmentVariableA("SOFTHSM2_CONF", value, size);
+       if (size == 0) {
+               return NULL;
+       }
+
+       value = (LPSTR) malloc(size);
+       if (NULL == value) {
+               return NULL;
+       }
+
+       if (GetEnvironmentVariableA("SOFTHSM2_CONF", value, size) != (size - 1)) {
+               free(value);
+               return NULL;
+       }
+
+       return value;
+
+#else
+
+       char *value = getenv("SOFTHSM2_CONF");
+
+       if (value == NULL) {
+               return value;
+       } else {
+               return strdup(value);
+       }
+
+#endif
+}
+
+char* SimpleConfigLoader::getConfigPath()
+{
+       char* configPath = get_env_var_path();
+       char* tpath;
+
+       if (configPath != NULL)
+       {
+               return configPath;
+       }
+       else
+       {
+               tpath = get_user_path();
+               if (tpath != NULL)
+               {
+                       return tpath;
+               }
+       }
+
+       return strdup(DEFAULT_SOFTHSM2_CONF);
+}
+
+char* SimpleConfigLoader::trimString(char* text)
+{
+       if (text == NULL)
+       {
+               return NULL;
+       }
+
+       int startPos = 0;
+       int endPos = strlen(text) - 1;
+
+       // Find the first position without a space
+       while (startPos <= endPos && isspace((int)*(text + startPos)))
+       {
+               startPos++;
+       }
+       // Find the last position without a space
+       while (startPos <= endPos && isspace((int)*(text + endPos)))
+       {
+               endPos--;
+       }
+
+       // We must have a valid string
+       int length = endPos - startPos + 1;
+       if (length <= 0)
+       {
+               return NULL;
+       }
+
+       // Create the trimmed text
+       char* trimmedText = (char*)malloc(length + 1);
+       if (trimmedText == NULL)
+       {
+               return NULL;
+       }
+       trimmedText[length] = '\0';
+       memcpy(trimmedText, text + startPos, length);
+
+       return trimmedText;
+}
diff --git a/SoftHSMv2/src/lib/common/SimpleConfigLoader.h b/SoftHSMv2/src/lib/common/SimpleConfigLoader.h
new file mode 100644 (file)
index 0000000..e992cfb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010 .SE, The Internet Infrastructure Foundation
+ * 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.
+ */
+
+/*****************************************************************************
+ SimpleConfigLoader.h
+
+ Loads the configuration from the configuration file.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SIMPLECONFIGLOADER_H
+#define _SOFTHSM_V2_SIMPLECONFIGLOADER_H
+
+#include <memory>
+#include "config.h"
+#include "Configuration.h"
+
+class SimpleConfigLoader : public ConfigLoader
+{
+public:
+       static SimpleConfigLoader* i();
+
+       virtual ~SimpleConfigLoader() { }
+
+       virtual bool loadConfiguration();
+
+private:
+       SimpleConfigLoader();
+       char* getConfigPath();
+       char* trimString(char* text);
+       bool string2bool(std::string stringValue, bool* boolValue);
+
+#ifdef HAVE_CXX11
+       static std::unique_ptr<SimpleConfigLoader> instance;
+#else
+       static std::auto_ptr<SimpleConfigLoader> instance;
+#endif
+};
+
+#endif // !_SOFTHSM_V2_SIMPLECONFIGLOADER_H
+
diff --git a/SoftHSMv2/src/lib/common/fatal.cpp b/SoftHSMv2/src/lib/common/fatal.cpp
new file mode 100644 (file)
index 0000000..4da26f4
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ fatal.cpp
+
+ Implementens calls for handling fatal exceptions. When a fatal exception
+ occurs, this code ensures that as much of the securely allocated memory as
+ possible is wiped clean.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "fatal.h"
+#include "SecureMemoryRegistry.h"
+#include "cryptoki.h"
+
+void FatalException(void)
+{
+       try
+       {
+               DEBUG_MSG("Fatal exception handler called");
+       }
+       catch (...)
+       {
+       }
+
+       // Wipe as much of the securely allocated memory as possible
+       SecureMemoryRegistry::i()->wipe();
+
+       try
+       {
+               ERROR_MSG("A fatal exception occurred; exiting...");
+       }
+       catch (...)
+       {
+       }
+
+       exit(CKR_GENERAL_ERROR);
+}
+
diff --git a/SoftHSMv2/src/lib/common/fatal.h b/SoftHSMv2/src/lib/common/fatal.h
new file mode 100644 (file)
index 0000000..124265e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ fatal.h
+
+ Implementens calls for handling fatal exceptions. When a fatal exception
+ occurs, this code ensures that as much of the securely allocated memory as
+ possible is wiped clean.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_FATAL_H
+#define _SOFTHSM_V2_FATAL_H
+
+#include "config.h"
+#include "log.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif // __cplusplus
+
+void FatalException(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // !_SOFTHSM_V2_FATAL_H
+
diff --git a/SoftHSMv2/src/lib/common/log.cpp b/SoftHSMv2/src/lib/common/log.cpp
new file mode 100644 (file)
index 0000000..7400f6a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ log.cpp
+
+ Implements logging functions. This file is based on the concepts from
+ SoftHSM v1 but extends the logging functions with support for a variable
+ argument list as defined in stdarg (3).
+ *****************************************************************************/
+
+#include "config.h"
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <sstream>
+#include <vector>
+#include "log.h"
+
+int softLogLevel = LOG_DEBUG;
+
+bool setLogLevel(const std::string &loglevel)
+{
+       if (loglevel == "ERROR")
+       {
+               softLogLevel = LOG_ERR;
+       }
+       else if (loglevel == "WARNING")
+       {
+               softLogLevel = LOG_WARNING;
+       }
+       else if (loglevel == "INFO")
+       {
+               softLogLevel = LOG_INFO;
+       }
+       else if (loglevel == "DEBUG")
+       {
+               softLogLevel = LOG_DEBUG;
+       }
+       else
+       {
+               ERROR_MSG("Unknown value (%s) for log.level in configuration", loglevel.c_str());
+               return false;
+       }
+
+       return true;
+}
+
+void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
+{
+       if (loglevel > softLogLevel) return;
+
+       std::stringstream prepend;
+
+#ifdef SOFTHSM_LOG_FILE_AND_LINE
+       prepend << fileName << "(" << lineNo << ")";
+#ifndef SOFTHSM_LOG_FUNCTION_NAME
+       (void) functionName;
+       prepend << ":";
+#endif // !SOFTHSM_LOG_FUNCTION_NAME
+       prepend << " ";
+#endif // SOFTHSM_LOG_FILE_AND_LINE
+
+#ifdef SOFTHSM_LOG_FUNCTION_NAME
+       prepend << functionName << ": ";
+#endif // SOFTHSM_LOG_FUNCTION_NAME
+
+       // Print the format to a log message
+       std::vector<char> logMessage;
+       va_list args;
+
+       logMessage.resize(4096);
+
+       va_start(args, format);
+       vsnprintf(&logMessage[0], 4096, format, args);
+       va_end(args);
+
+       // And log it
+       syslog(loglevel, "%s%s", prepend.str().c_str(), &logMessage[0]);
+
+#ifdef DEBUG_LOG_STDERR
+       fprintf(stderr, "%s%s\n", prepend.str().c_str(), &logMessage[0]);
+       fflush(stderr);
+#endif // DEBUG_LOG_STDERR
+}
+
diff --git a/SoftHSMv2/src/lib/common/log.h b/SoftHSMv2/src/lib/common/log.h
new file mode 100644 (file)
index 0000000..cf91aaf
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ log.h
+
+ Implements logging functions. This file is based on the concepts from 
+ SoftHSM v1 but extends the logging functions with support for a variable
+ argument list as defined in stdarg (3).
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_LOG_H
+#define _SOFTHSM_V2_LOG_H
+
+#include "config.h"
+
+#include <syslog.h>
+#include <string>
+
+/* Unset this define if you don't want to log the source file name and line number */
+#define SOFTHSM_LOG_FILE_AND_LINE
+
+/* Set this define to log the function name */
+/* #define SOFTHSM_LOG_FUNCTION_NAME */
+
+/* Define this symbol (either here or in the build setup) to log to stderr */
+/* #define DEBUG_LOG_STDERR */
+
+/* Logging errors */
+#ifndef _WIN32
+#define ERROR_MSG(...) softHSMLog(LOG_ERR, __func__, __FILE__, __LINE__, __VA_ARGS__);
+#else
+#define ERROR_MSG(...) softHSMLog(LOG_ERR, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);
+#endif
+
+/* Logging warnings */
+#ifndef _WIN32
+#define WARNING_MSG(...) softHSMLog(LOG_WARNING, __func__, __FILE__, __LINE__, __VA_ARGS__);
+#else
+#define WARNING_MSG(...) softHSMLog(LOG_WARNING, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);
+#endif
+
+/* Logging information */
+#ifndef _WIN32
+#define INFO_MSG(...) softHSMLog(LOG_INFO, __func__, __FILE__, __LINE__, __VA_ARGS__);
+#else
+#define INFO_MSG(...) softHSMLog(LOG_INFO, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);
+#endif
+
+/* Logging debug information */
+#ifndef _WIN32
+#define DEBUG_MSG(...) softHSMLog(LOG_DEBUG, __func__, __FILE__, __LINE__, __VA_ARGS__);
+#else
+#define DEBUG_MSG(...) softHSMLog(LOG_DEBUG, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);
+#endif
+
+/* Function definitions */
+bool setLogLevel(const std::string &loglevel);
+void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...);
+
+#endif /* !_SOFTHSM_V2_LOG_H */
+
diff --git a/SoftHSMv2/src/lib/common/osmutex.cpp b/SoftHSMv2/src/lib/common/osmutex.cpp
new file mode 100644 (file)
index 0000000..28db10e
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2008-2010 .SE (The Internet Infrastructure Foundation).
+ * 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.
+ */
+
+/*****************************************************************************
+ osmutex.cpp
+
+ Contains OS-specific implementations of intraprocess mutex functions. This
+ implementation is based on SoftHSM v1
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "osmutex.h"
+
+#ifdef HAVE_PTHREAD_H
+
+#include <stdlib.h>
+#include <pthread.h>
+
+CK_RV OSCreateMutex(CK_VOID_PTR_PTR newMutex)
+{
+       int rv;
+
+       /* Allocate memory */
+       pthread_mutex_t* pthreadMutex = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t));
+
+       if (pthreadMutex == NULL)
+       {
+               ERROR_MSG("Failed to allocate memory for a new mutex");
+
+               return CKR_HOST_MEMORY;
+       }
+
+       /* Initialise the mutex */
+       if ((rv = pthread_mutex_init(pthreadMutex, NULL)) != 0)
+       {
+               free(pthreadMutex);
+
+               ERROR_MSG("Failed to initialise POSIX mutex (0x%08X)", rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       *newMutex = pthreadMutex;
+
+       return CKR_OK;
+}
+
+CK_RV OSDestroyMutex(CK_VOID_PTR mutex)
+{
+       int rv;
+       pthread_mutex_t* pthreadMutex = (pthread_mutex_t*) mutex;
+
+       if (pthreadMutex == NULL)
+       {
+               ERROR_MSG("Cannot destroy NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       if ((rv = pthread_mutex_destroy(pthreadMutex)) != 0)
+       {
+               ERROR_MSG("Failed to destroy POSIX mutex (0x%08X)", rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       free(pthreadMutex);
+
+       return CKR_OK;
+}
+
+CK_RV OSLockMutex(CK_VOID_PTR mutex)
+{
+       int rv;
+       pthread_mutex_t* pthreadMutex = (pthread_mutex_t*) mutex;
+
+       if (pthreadMutex == NULL)
+       {
+               ERROR_MSG("Cannot lock NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       if ((rv = pthread_mutex_lock(pthreadMutex)) != 0)
+       {
+               ERROR_MSG("Failed to lock POSIX mutex 0x%08X (0x%08X)", pthreadMutex, rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+CK_RV OSUnlockMutex(CK_VOID_PTR mutex)
+{
+       int rv;
+       pthread_mutex_t* pthreadMutex = (pthread_mutex_t*) mutex;
+
+       if (pthreadMutex == NULL)
+       {
+               ERROR_MSG("Cannot unlock NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       if ((rv = pthread_mutex_unlock(pthreadMutex)) != 0)
+       {
+               ERROR_MSG("Failed to unlock POSIX mutex 0x%08X (0x%08X)", pthreadMutex, rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+#elif _WIN32
+
+CK_RV OSCreateMutex(CK_VOID_PTR_PTR newMutex)
+{
+       HANDLE hMutex;
+
+       hMutex = CreateMutex(NULL, FALSE, NULL);
+       if (hMutex == NULL)
+       {
+               DWORD rv = GetLastError();
+
+               ERROR_MSG("Failed to initialise WIN32 mutex (0x%08X)", rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       *newMutex = hMutex;
+
+       return CKR_OK;
+}
+
+CK_RV OSDestroyMutex(CK_VOID_PTR mutex)
+{
+       HANDLE hMutex = (HANDLE) mutex;
+
+       if (hMutex == NULL)
+       {
+               ERROR_MSG("Cannot destroy NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       if (CloseHandle(hMutex) == 0)
+       {
+               DWORD rv = GetLastError();
+
+               ERROR_MSG("Failed to destroy WIN32 mutex (0x%08X)", rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+CK_RV OSLockMutex(CK_VOID_PTR mutex)
+{
+       DWORD rv;
+       HANDLE hMutex = (HANDLE) mutex;
+
+       if (hMutex == NULL)
+       {
+               ERROR_MSG("Cannot lock NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       rv = WaitForSingleObject(hMutex, INFINITE);
+       if (rv != WAIT_OBJECT_0)
+       {
+               // WAIT_ABANDONED 0x00000080
+               // WAIT_OBJECT_0  0x00000000
+               // WAIT_TIMEOUT   0x00000102
+               // WAIT_FAILED    0xFFFFFFFF
+
+               if (rv == WAIT_FAILED)
+                       rv = GetLastError();
+
+               ERROR_MSG("Failed to lock WIN32 mutex 0x%08X (0x%08X)", hMutex, rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+CK_RV OSUnlockMutex(CK_VOID_PTR mutex)
+{
+       HANDLE hMutex = (HANDLE) mutex;
+
+       if (hMutex == NULL)
+       {
+               ERROR_MSG("Cannot unlock NULL mutex");
+
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       if (ReleaseMutex(hMutex) == 0)
+       {
+               DWORD rv = GetLastError();
+
+               ERROR_MSG("Failed to unlock WIN32 mutex 0x%08X (0x%08X)", hMutex, rv);
+
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+#else
+#error "There are no mutex implementations for your operating system yet"
+#endif
+
diff --git a/SoftHSMv2/src/lib/common/osmutex.h b/SoftHSMv2/src/lib/common/osmutex.h
new file mode 100644 (file)
index 0000000..103dc67
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008-2010 .SE (The Internet Infrastructure Foundation).
+ * 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.
+ */
+
+/*****************************************************************************
+ osmutex.h
+
+ Contains OS-specific implementations of intraprocess mutex functions. This
+ implementation is based on SoftHSM v1
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSMUTEX_H
+#define _SOFTHSM_V2_OSMUTEX_H
+
+#include "config.h"
+#include "cryptoki.h"
+
+CK_RV OSCreateMutex(CK_VOID_PTR_PTR newMutex);
+CK_RV OSDestroyMutex(CK_VOID_PTR mutex);
+CK_RV OSLockMutex(CK_VOID_PTR mutex);
+CK_RV OSUnlockMutex(CK_VOID_PTR mutex);
+
+#endif /* !_SOFTHSM_V2_OSMUTEX_H */
+
diff --git a/SoftHSMv2/src/lib/common/softhsm2.conf.5.in b/SoftHSMv2/src/lib/common/softhsm2.conf.5.in
new file mode 100644 (file)
index 0000000..5291a09
--- /dev/null
@@ -0,0 +1,86 @@
+.TH softhsm2.conf 5 "30 October 2014" "SoftHSM"
+.SH NAME
+softhsm2.conf \- SoftHSM configuration file
+.SH SYNOPSIS
+.B softhsm2.conf
+.SH DESCRIPTION
+This is the configuration file for SoftHSM. It can be found on a
+default location, but can also be relocated by using the
+environment variable. Any configuration must be done according
+to the file format found in this document.
+.SH FILE FORMAT
+Each configuration option is a pair of name and value separated by
+a equality sign. The configuration option must be located on a single line.
+.LP
+.RS
+.nf
+<name> = <value>
+.fi
+.RE
+.LP
+It is also possible to add comments in the file by using the hash sign.
+Anything after the hash sign will be ignored.
+.LP
+.RS
+.nf
+# A comment
+.RE
+.LP
+Any empty lines or lines that does not have the correct format will be ignored.
+.SH DIRECTORIES.TOKENDIR
+The location where SoftHSM can store the tokens.
+.LP
+.RS
+.nf
+directories.tokendir = @softhsmtokendir@
+.fi
+.RE
+.LP
+.SH OBJECTSTORE.BACKEND
+The backend to use by SoftHSM to store token objects. Either "file" or "db" is supported.
+In order to use the "db" backend, the SoftHSM build needs to be configured with "configure --with-objectstore-backend-db"
+.LP
+.RS
+.nf
+objectstore.backend = file
+.fi
+.RE
+.LP
+.SH LOG.LEVEL
+The log level which can be set to ERROR, WARNING, INFO or DEBUG.
+.LP
+.RS
+.nf
+log.level = INFO
+.fi
+.RE
+.LP
+.SH SLOTS.REMOVABLE
+If set to true CKF_REMOVABLE_DEVICE is set in the flags returned by C_GetSlotInfo. Default is false.
+.LP
+.RS
+.nf
+slots.removable = true
+.fi
+.RE
+.LP
+.SH ENVIRONMENT
+.TP
+SOFTHSM2_CONF
+When defined, the value will be used as path to the configuration file.
+.SH FILES
+.TP
+.I ~/.config/softhsm2/softhsm2.conf
+default user-specific location of the SoftHSM configuration file; if it exists it will override the system wide configuration
+.TP
+.I @default_softhsm2_conf@
+default system-wide location of the SoftHSM configuration file
+.TP
+.I @default_softhsm2_conf@.sample
+an example of a SoftHSM configuration file
+.SH AUTHOR
+Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk.
+.SH "SEE ALSO"
+.IR softhsm2-keyconv (1),
+.IR softhsm2-migrate (1),
+.IR softhsm2-util (1)
diff --git a/SoftHSMv2/src/lib/common/softhsm2.conf.in b/SoftHSMv2/src/lib/common/softhsm2.conf.in
new file mode 100644 (file)
index 0000000..3d5728d
--- /dev/null
@@ -0,0 +1,10 @@
+# SoftHSM v2 configuration file
+
+directories.tokendir = @softhsmtokendir@
+objectstore.backend = file
+
+# ERROR, WARNING, INFO, DEBUG
+log.level = ERROR
+
+# If CKF_REMOVABLE_DEVICE flag should be set
+slots.removable = false
diff --git a/SoftHSMv2/src/lib/crypto/AESKey.cpp b/SoftHSMv2/src/lib/crypto/AESKey.cpp
new file mode 100644 (file)
index 0000000..9b511b5
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AESKey.cpp
+
+ AES key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+#include "AESKey.h"
+#include "CryptoFactory.h"
+
+// Get key check value
+ByteString AESKey::getKeyCheckValue() const
+{
+       ByteString iv;
+       ByteString data;
+       ByteString encryptedData;
+       ByteString encryptedFinal;
+
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
+       if (cipher == NULL) return encryptedData;
+
+       // Single block of null (0x00) bytes
+       data.resize(cipher->getBlockSize());
+       memset(&data[0], 0, data.size());
+
+       if (!cipher->encryptInit(this, SymMode::ECB, iv, false) ||
+           !cipher->encryptUpdate(data, encryptedData) ||
+           !cipher->encryptFinal(encryptedFinal))
+       {
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return encryptedData;
+       }
+       CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+
+       encryptedData += encryptedFinal;
+       encryptedData.resize(3);
+
+       return encryptedData;
+}
diff --git a/SoftHSMv2/src/lib/crypto/AESKey.h b/SoftHSMv2/src/lib/crypto/AESKey.h
new file mode 100644 (file)
index 0000000..6505b9d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AESKey.h
+
+ AES key symmetric key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_AESKEY_H
+#define _SOFTHSM_V2_AESKEY_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "SymmetricKey.h"
+
+class AESKey : public SymmetricKey
+{
+public:
+       // Base constructor
+       AESKey(size_t inBitLen = 0) : SymmetricKey(inBitLen) { }
+
+       // Get the key check value
+       virtual ByteString getKeyCheckValue() const;
+};
+
+#endif // !SOFTHSM_V2_AESKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp
new file mode 100644 (file)
index 0000000..20a50a5
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymmetricAlgorithm.cpp
+
+ Base class for asymmetric algorithm classes
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "AsymmetricAlgorithm.h"
+
+// Base constructor
+AsymmetricAlgorithm::AsymmetricAlgorithm()
+{
+       currentOperation = NONE;
+       currentMechanism = AsymMech::Unknown;
+       currentPadding = AsymMech::Unknown;
+       currentPublicKey = NULL;
+       currentPrivateKey = NULL;
+}
+
+// Signing functions
+bool AsymmetricAlgorithm::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                              ByteString& signature, const AsymMech::Type mechanism,
+                              const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       // Compose from multi-part operations
+       return (signInit(privateKey, mechanism, param, paramLen) && signUpdate(dataToSign) && signFinal(signature));
+}
+
+bool AsymmetricAlgorithm::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                                  const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       if ((currentOperation != NONE) || (privateKey == NULL))
+       {
+               return false;
+       }
+
+       currentPrivateKey = privateKey;
+       currentMechanism = mechanism;
+       currentOperation = SIGN;
+
+       return true;
+}
+
+bool AsymmetricAlgorithm::signUpdate(const ByteString& /*dataToSign*/)
+{
+       if (currentOperation != SIGN)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool AsymmetricAlgorithm::signFinal(ByteString& /*signature*/)
+{
+       if (currentOperation != SIGN)
+       {
+               return false;
+       }
+
+       currentOperation = NONE;
+       currentPrivateKey = NULL;
+       currentMechanism = AsymMech::Unknown;
+
+       return true;
+}
+
+// Verification functions
+bool AsymmetricAlgorithm::verify(PublicKey* publicKey, const ByteString& originalData,
+                                const ByteString& signature, const AsymMech::Type mechanism,
+                                const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       // Compose from multi-part operations
+       return (verifyInit(publicKey, mechanism, param, paramLen) && verifyUpdate(originalData) && verifyFinal(signature));
+}
+
+bool AsymmetricAlgorithm::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                                    const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       if ((currentOperation != NONE) || (publicKey == NULL))
+       {
+               return false;
+       }
+
+       currentOperation = VERIFY;
+       currentPublicKey = publicKey;
+       currentMechanism = mechanism;
+
+       return true;
+}
+
+bool AsymmetricAlgorithm::verifyUpdate(const ByteString& /*originalData*/)
+{
+       if (currentOperation != VERIFY)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool AsymmetricAlgorithm::verifyFinal(const ByteString& /*signature*/)
+{
+       if (currentOperation != VERIFY)
+       {
+               return false;
+       }
+
+       currentOperation = NONE;
+       currentPublicKey = NULL;
+       currentMechanism = AsymMech::Unknown;
+
+       return true;
+}
+
+// Returns true for mechanisms which have 'tick mark' in Wrap&Unwrap column in PKCS #11 Mechanisms v2.40
+bool AsymmetricAlgorithm::isWrappingMech(AsymMech::Type padding)
+{
+       switch (padding)
+       {
+               case AsymMech::RSA:
+               case AsymMech::RSA_PKCS:
+               case AsymMech::RSA_PKCS_OAEP:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+// Wrap/Unwrap keys
+bool AsymmetricAlgorithm::wrapKey(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding)
+{
+       if (!isWrappingMech(padding))
+               return false;
+
+       return encrypt(publicKey, data, encryptedData, padding);
+}
+
+bool AsymmetricAlgorithm::unwrapKey(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding)
+{
+       if (!isWrappingMech(padding))
+               return false;
+
+       return decrypt(privateKey, encryptedData, data, padding);
+}
+
+
+bool AsymmetricAlgorithm::generateParameters(AsymmetricParameters** /*ppParams*/, void* /*parameters = NULL*/, RNG* /*rng = NULL*/)
+{
+       return false;
+}
+
+bool AsymmetricAlgorithm::deriveKey(SymmetricKey** /*ppSymmetricKey*/, PublicKey* /*publicKey*/, PrivateKey* /*privateKey*/)
+{
+       return false;
+}
+
+bool AsymmetricAlgorithm::reconstructParameters(AsymmetricParameters** /*ppParams*/, ByteString& /*serialisedData*/)
+{
+       return false;
+}
+
+AsymmetricParameters* AsymmetricAlgorithm::newParameters()
+{
+       return NULL;
+}
+
+// Key recycling -- override these functions in a derived class if you need to perform specific cleanup
+void AsymmetricAlgorithm::recycleKeyPair(AsymmetricKeyPair* toRecycle)
+{
+       delete toRecycle;
+}
+
+void AsymmetricAlgorithm::recycleParameters(AsymmetricParameters* toRecycle)
+{
+       delete toRecycle;
+}
+
+void AsymmetricAlgorithm::recyclePublicKey(PublicKey* toRecycle)
+{
+       delete toRecycle;
+}
+
+void AsymmetricAlgorithm::recyclePrivateKey(PrivateKey* toRecycle)
+{
+       delete toRecycle;
+}
+
+void AsymmetricAlgorithm::recycleSymmetricKey(SymmetricKey* toRecycle)
+{
+       delete toRecycle;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h b/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h
new file mode 100644 (file)
index 0000000..ca0d840
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymmetricAlgorithm.h
+
+ Base class for asymmetric algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ASYMMETRICALGORITHM_H
+#define _SOFTHSM_V2_ASYMMETRICALGORITHM_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricParameters.h"
+#include "HashAlgorithm.h"
+#include "PublicKey.h"
+#include "PrivateKey.h"
+#include "RNG.h"
+#include "SymmetricKey.h"
+
+struct AsymAlgo
+{
+        enum Type
+       {
+               Unknown,
+               RSA,
+               DSA,
+               DH,
+               ECDH,
+               ECDSA,
+               GOST
+        };
+};
+
+struct AsymMech
+{
+       enum Type
+       {
+               Unknown,
+               RSA,
+               RSA_MD5_PKCS,
+               RSA_PKCS,
+               RSA_PKCS_OAEP,
+               RSA_SHA1_PKCS,
+               RSA_SHA224_PKCS,
+               RSA_SHA256_PKCS,
+               RSA_SHA384_PKCS,
+               RSA_SHA512_PKCS,
+               RSA_PKCS_PSS,
+               RSA_SHA1_PKCS_PSS,
+               RSA_SHA224_PKCS_PSS,
+               RSA_SHA256_PKCS_PSS,
+               RSA_SHA384_PKCS_PSS,
+               RSA_SHA512_PKCS_PSS,
+               RSA_SSL,
+               DSA,
+               DSA_SHA1,
+               DSA_SHA224,
+               DSA_SHA256,
+               DSA_SHA384,
+               DSA_SHA512,
+               ECDSA,
+               GOST,
+               GOST_GOST
+       };
+};
+
+struct AsymRSAMGF
+{
+       enum Type
+       {
+               Unknown,
+               MGF1_SHA1,
+               MGF1_SHA224,
+               MGF1_SHA256,
+               MGF1_SHA384,
+               MGF1_SHA512
+       };
+};
+
+struct RSA_PKCS_PSS_PARAMS
+{
+       HashAlgo::Type hashAlg;
+       AsymRSAMGF::Type mgf;
+       size_t sLen;
+};
+
+class AsymmetricAlgorithm
+{
+public:
+       // Base constructors
+       AsymmetricAlgorithm();
+
+       // Destructor
+       virtual ~AsymmetricAlgorithm() { }
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding) = 0;
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding) = 0;
+
+       // Wrap/Unwrap keys
+       bool wrapKey(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+       bool unwrapKey(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL) = 0;
+       virtual unsigned long getMinKeySize() = 0;
+       virtual unsigned long getMaxKeySize() = 0;
+       virtual bool generateParameters(AsymmetricParameters** ppParams, void* parameters = NULL, RNG* rng = NULL);
+       virtual bool deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData) = 0;
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData) = 0;
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData) = 0;
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey() = 0;
+       virtual PrivateKey* newPrivateKey() = 0;
+       virtual AsymmetricParameters* newParameters();
+
+       // Key recycling -- override these functions in a derived class if you need to perform specific cleanup
+       virtual void recycleKeyPair(AsymmetricKeyPair* toRecycle);
+       virtual void recycleParameters(AsymmetricParameters* toRecycle);
+       virtual void recyclePublicKey(PublicKey* toRecycle);
+       virtual void recyclePrivateKey(PrivateKey* toRecycle);
+       virtual void recycleSymmetricKey(SymmetricKey* toRecycle);
+
+protected:
+       PublicKey* currentPublicKey;
+       PrivateKey* currentPrivateKey;
+
+       AsymMech::Type currentMechanism;
+       AsymMech::Type currentPadding;
+
+private:
+       enum
+       {
+               NONE,
+               SIGN,
+               VERIFY
+       }
+       currentOperation;
+
+       bool isWrappingMech(AsymMech::Type padding);
+};
+
+#endif // !_SOFTHSM_V2_ASYMMETRICALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp b/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp
new file mode 100644 (file)
index 0000000..a31c17e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymmetricKeyPair.cpp
+
+ Asymmetric key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "AsymmetricKeyPair.h"
+
+ByteString AsymmetricKeyPair::serialise() const
+{
+       return getConstPublicKey()->serialise().serialise() + getConstPrivateKey()->serialise().serialise();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h b/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h
new file mode 100644 (file)
index 0000000..8ff63ef
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymmetricKeyPair.h
+
+ Base class for asymmetric key-pair classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ASYMMETRICKEYPAIR_H
+#define _SOFTHSM_V2_ASYMMETRICKEYPAIR_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "PublicKey.h"
+#include "PrivateKey.h"
+#include "Serialisable.h"
+
+class AsymmetricKeyPair : public Serialisable
+{
+public:
+       // Base constructors
+       AsymmetricKeyPair() { }
+
+       AsymmetricKeyPair(const AsymmetricKeyPair& /*in*/) { }
+
+       // Destructor
+       virtual ~AsymmetricKeyPair() { }
+
+       // Return the public key
+       virtual PublicKey* getPublicKey() = 0;
+       virtual const PublicKey* getConstPublicKey() const = 0;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey() = 0;
+       virtual const PrivateKey* getConstPrivateKey() const = 0;
+
+       // Serialise the contents
+       virtual ByteString serialise() const;
+};
+
+#endif // !_SOFTHSM_V2_ASYMMETRICKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/AsymmetricParameters.h b/SoftHSMv2/src/lib/crypto/AsymmetricParameters.h
new file mode 100644 (file)
index 0000000..12c607b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymmetricParameters.h
+
+ Base class for asymmetric parameter classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ASYMMETRICPARAMETERS_H
+#define _SOFTHSM_V2_ASYMMETRICPARAMETERS_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+
+class AsymmetricParameters : public Serialisable
+{
+public:
+       // Base constructors
+       AsymmetricParameters() { }
+
+       AsymmetricParameters(const AsymmetricParameters& /*in*/) { }
+
+       // Destructor
+       virtual ~AsymmetricParameters() { }
+
+       // Check if it is of the given type
+       virtual bool areOfType(const char* type) = 0;
+
+       // Serialisation
+       virtual ByteString serialise() const = 0;
+};
+
+#endif // !_SOFTHSM_V2_ASYMMETRICPARAMETERS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanAES.cpp b/SoftHSMv2/src/lib/crypto/BotanAES.cpp
new file mode 100644 (file)
index 0000000..0c67a09
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanAES.cpp
+
+ Botan AES implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanAES.h"
+#include <algorithm>
+#include <botan/rfc3394.h>
+#include <botan/version.h>
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+#include <botan/libstate.h>
+#endif
+
+// Wrap/Unwrap keys
+bool BotanAES::wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out)
+{
+       // Check key bit length; AES only supports 128, 192 or 256 bit keys
+       if ((key->getBitLen() != 128) &&
+           (key->getBitLen() != 192) &&
+           (key->getBitLen() != 256))
+       {
+               ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen());
+
+               return false;
+       }
+
+       // Determine the wrapping mode
+       if (mode == SymWrap::AES_KEYWRAP)
+       {
+               // RFC 3394 AES key wrap
+               if (in.size() < 16)
+               {
+                       ERROR_MSG("key data to wrap too small");
+
+                       return false;
+               }
+               if ((in.size() % 8) != 0)
+               {
+                       ERROR_MSG("key data to wrap not aligned");
+
+                       return false;
+               }
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> data(in.size());
+               memcpy(data.data(), in.const_byte_str(), in.size());
+               Botan::secure_vector<Botan::byte> wrapped;
+#else
+               Botan::MemoryVector<Botan::byte> data(in.size());
+               memcpy(data.begin(), in.const_byte_str(), in.size());
+               Botan::SecureVector<Botan::byte> wrapped;
+#endif
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+               Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory();
+               try
+               {
+                       wrapped = Botan::rfc3394_keywrap(data, botanKey, af);
+               }
+#else
+               try
+               {
+                       wrapped = Botan::rfc3394_keywrap(data, botanKey);
+               }
+#endif
+               catch (...)
+               {
+                       ERROR_MSG("AES key wrap failed");
+
+                       return false;
+               }
+               out.resize(wrapped.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&out[0], wrapped.data(), out.size());
+#else
+               memcpy(&out[0], wrapped.begin(), out.size());
+#endif
+
+               return  true;
+       }
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       else if (mode == SymWrap::AES_KEYWRAP_PAD)
+       {
+               // RFC 5649 AES key wrap with pad
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> data(in.size());
+               memcpy(data.data(), in.const_byte_str(), in.size());
+               Botan::secure_vector<Botan::byte> wrapped;
+#else
+               Botan::MemoryVector<Botan::byte> data(in.size());
+               memcpy(data.begin(), in.const_byte_str(), in.size());
+               Botan::SecureVector<Botan::byte> wrapped;
+#endif
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+               Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory();
+               try
+               {
+                       wrapped = Botan::rfc5649_keywrap(data, botanKey, af);
+               }
+#else
+               try
+               {
+                       wrapped = Botan::rfc5649_keywrap(data, botanKey);
+               }
+#endif
+               catch (...)
+               {
+                       ERROR_MSG("AES key wrap failed");
+
+                       return false;
+               }
+               out.resize(wrapped.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&out[0], wrapped.data(), out.size());
+#else
+               memcpy(&out[0], wrapped.begin(), out.size());
+#endif
+
+               return  true;
+       }
+#endif
+       else
+       {
+               ERROR_MSG("unknown AES key wrap mode %i", mode);
+
+               return false;
+       }
+}
+
+bool BotanAES::unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out)
+{
+       // Check key bit length; AES only supports 128, 192 or 256 bit keys
+       if ((key->getBitLen() != 128) &&
+           (key->getBitLen() != 192) &&
+           (key->getBitLen() != 256))
+       {
+               ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen());
+
+               return false;
+       }
+
+       // Determine the unwrapping mode
+       if (mode == SymWrap::AES_KEYWRAP)
+       {
+               // RFC 3394 AES key wrap
+               if (in.size() < 24)
+               {
+                       ERROR_MSG("key data to unwrap too small");
+
+                       return false;
+               }
+               if ((in.size() % 8) != 0)
+               {
+                       ERROR_MSG("key data to unwrap not aligned");
+
+                       return false;
+               }
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> wrapped(in.size());
+               memcpy(wrapped.data(), in.const_byte_str(), in.size());
+               Botan::secure_vector<Botan::byte> unwrapped;
+#else
+               Botan::MemoryVector<Botan::byte> wrapped(in.size());
+               memcpy(wrapped.begin(), in.const_byte_str(), in.size());
+               Botan::SecureVector<Botan::byte> unwrapped;
+#endif
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+               Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory();
+               try
+               {
+                       unwrapped = Botan::rfc3394_keyunwrap(wrapped, botanKey, af);
+               }
+#else
+               try
+               {
+                       unwrapped = Botan::rfc3394_keyunwrap(wrapped, botanKey);
+               }
+#endif
+               catch (...)
+               {
+                       ERROR_MSG("AES key unwrap failed");
+
+                       return false;
+               }
+               out.resize(unwrapped.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&out[0], unwrapped.data(), out.size());
+#else
+               memcpy(&out[0], unwrapped.begin(), out.size());
+#endif
+
+               return  true;
+       }
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       else if (mode == SymWrap::AES_KEYWRAP_PAD)
+       {
+               // RFC 5649 AES key wrap with wrap
+               if (in.size() < 16)
+               {
+                       ERROR_MSG("key data to unwrap too small");
+
+                       return false;
+               }
+               if ((in.size() % 8) != 0)
+               {
+                       ERROR_MSG("key data to unwrap not aligned");
+
+                       return false;
+               }
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> wrapped(in.size());
+               memcpy(wrapped.data(), in.const_byte_str(), in.size());
+               Botan::secure_vector<Botan::byte> unwrapped;
+#else
+               Botan::MemoryVector<Botan::byte> wrapped(in.size());
+               memcpy(wrapped.begin(), in.const_byte_str(), in.size());
+               Botan::SecureVector<Botan::byte> unwrapped;
+#endif
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+               Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory();
+               try
+               {
+                       unwrapped = Botan::rfc5649_keyunwrap(wrapped, botanKey, af);
+               }
+#else
+               try
+               {
+                       unwrapped = Botan::rfc5649_keyunwrap(wrapped, botanKey);
+               }
+#endif
+               catch (...)
+               {
+                       ERROR_MSG("AES key unwrap failed");
+
+                       return false;
+               }
+               out.resize(unwrapped.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&out[0], unwrapped.data(), out.size());
+#else
+               memcpy(&out[0], unwrapped.begin(), out.size());
+#endif
+
+               return  true;
+       }
+#endif
+       else
+       {
+               ERROR_MSG("unknown AES key wrap mode %i", mode);
+
+               return false;
+       }
+}
+
+std::string BotanAES::getCipher() const
+{
+       std::string algo;
+       std::string mode;
+       std::string padding;
+
+       if (currentKey == NULL) return "";
+
+       // Check currentKey bit length; AES only supports 128, 192 or 256 bit keys
+       switch (currentKey->getBitLen())
+       {
+               case 128:
+                       algo = "AES-128";
+                       break;
+               case 192:
+                       algo = "AES-192";
+                       break;
+               case 256:
+                       algo = "AES-256";
+                       break;
+               default:
+                       ERROR_MSG("Invalid AES currentKey length (%d bits)", currentKey->getBitLen());
+
+                       return "";
+       }
+
+       // Determine the cipher mode
+       switch (currentCipherMode)
+       {
+               case SymMode::CBC:
+                       mode = "CBC";
+                       break;
+               case SymMode::CTR:
+                       return algo + "/CTR-BE";
+               case SymMode::ECB:
+                       mode = "ECB";
+                       break;
+#ifdef WITH_AES_GCM
+               case SymMode::GCM:
+                       return algo + "/GCM(" + std::to_string(currentTagBytes) + ")";
+#endif
+               default:
+                       ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode);
+
+                       return "";
+       }
+
+       // Check padding mode
+       if (currentPaddingMode)
+       {
+               padding = "PKCS7";
+       }
+       else
+       {
+               padding = "NoPadding";
+       }
+
+       return algo + "/" + mode + "/" + padding;
+}
+
+size_t BotanAES::getBlockSize() const
+{
+       // The block size is 128 bits
+       return 128 >> 3;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanAES.h b/SoftHSMv2/src/lib/crypto/BotanAES.h
new file mode 100644 (file)
index 0000000..4bc38ab
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanAES.h
+
+ Botan AES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANAES_H
+#define _SOFTHSM_V2_BOTANAES_H
+
+#include <string>
+#include "config.h"
+#include "BotanSymmetricAlgorithm.h"
+
+class BotanAES : public BotanSymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~BotanAES() { }
+
+       // Wrap/Unwrap keys
+       virtual bool wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       virtual bool unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       // Return the block size
+       virtual size_t getBlockSize() const;
+
+protected:
+       // Return the right Botan cipher for the operation
+       virtual std::string getCipher() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANAES_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp b/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp
new file mode 100644 (file)
index 0000000..b4df224
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanCryptoFactory.cpp
+
+ This is a Botan based cryptographic algorithm factory
+ *****************************************************************************/
+#include "config.h"
+#include "BotanCryptoFactory.h"
+#include "BotanAES.h"
+#include "BotanDES.h"
+#include "BotanDSA.h"
+#include "BotanDH.h"
+#ifdef WITH_ECC
+#include "BotanECDH.h"
+#include "BotanECDSA.h"
+#endif
+#include "BotanMD5.h"
+#include "BotanRNG.h"
+#include "BotanRSA.h"
+#include "BotanSHA1.h"
+#include "BotanSHA224.h"
+#include "BotanSHA256.h"
+#include "BotanSHA384.h"
+#include "BotanSHA512.h"
+#ifdef WITH_GOST
+#include "BotanGOST.h"
+#include "BotanGOSTR3411.h"
+#endif
+#include "BotanMAC.h"
+
+#include <botan/init.h>
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+#include <botan/libstate.h>
+#endif
+
+// Constructor
+BotanCryptoFactory::BotanCryptoFactory()
+{
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       wasInitialized = false;
+
+       // Check if Botan has already been initialized
+       if (Botan::Global_State_Management::global_state_exists())
+       {
+               wasInitialized = true;
+       }
+
+       // Init the Botan crypto library
+       if (!wasInitialized)
+       {
+               Botan::LibraryInitializer::initialize("thread_safe=true");
+       }
+#else
+       Botan::LibraryInitializer::initialize("thread_safe=true");
+#endif
+
+       // Create mutex
+       rngsMutex = MutexFactory::i()->getMutex();
+}
+
+// Destructor
+BotanCryptoFactory::~BotanCryptoFactory()
+{
+       // Delete the RNGs
+#ifdef HAVE_PTHREAD_H
+       std::map<pthread_t,RNG*>::iterator it;
+       for (it=rngs.begin(); it != rngs.end(); it++)
+       {
+               delete (BotanRNG*)it->second;
+       }
+#elif _WIN32
+       std::map<DWORD,RNG*>::iterator it;
+       for (it=rngs.begin(); it != rngs.end(); it++)
+       {
+               delete (BotanRNG*)it->second;
+       }
+#endif
+
+       // Delete the mutex
+       MutexFactory::i()->recycleMutex(rngsMutex);
+
+       // Deinitialize the Botan crypto lib
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       if (!wasInitialized)
+       {
+               Botan::LibraryInitializer::deinitialize();
+       }
+#else
+       Botan::LibraryInitializer::deinitialize();
+#endif
+}
+
+// Return the one-and-only instance
+BotanCryptoFactory* BotanCryptoFactory::i()
+{
+       if (!instance.get())
+       {
+               instance.reset(new BotanCryptoFactory());
+       }
+
+       return instance.get();
+}
+
+// This will destroy the one-and-only instance.
+void BotanCryptoFactory::reset()
+{
+       instance.reset();
+}
+
+// Create a concrete instance of a symmetric algorithm
+SymmetricAlgorithm* BotanCryptoFactory::getSymmetricAlgorithm(SymAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case SymAlgo::AES:
+                       return new BotanAES();
+               case SymAlgo::DES:
+               case SymAlgo::DES3:
+                       return new BotanDES();
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of an asymmetric algorithm
+AsymmetricAlgorithm* BotanCryptoFactory::getAsymmetricAlgorithm(AsymAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case AsymAlgo::RSA:
+                       return new BotanRSA();
+               case AsymAlgo::DSA:
+                       return new BotanDSA();
+               case AsymAlgo::DH:
+                       return new BotanDH();
+#ifdef WITH_ECC
+               case AsymAlgo::ECDH:
+                       return new BotanECDH();
+               case AsymAlgo::ECDSA:
+                       return new BotanECDSA();
+#endif
+#ifdef WITH_GOST
+               case AsymAlgo::GOST:
+                       return new BotanGOST();
+#endif
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of a hash algorithm
+HashAlgorithm* BotanCryptoFactory::getHashAlgorithm(HashAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case HashAlgo::MD5:
+                       return new BotanMD5();
+               case HashAlgo::SHA1:
+                       return new BotanSHA1();
+               case HashAlgo::SHA224:
+                       return new BotanSHA224();
+               case HashAlgo::SHA256:
+                       return new BotanSHA256();
+               case HashAlgo::SHA384:
+                       return new BotanSHA384();
+               case HashAlgo::SHA512:
+                       return new BotanSHA512();
+#ifdef WITH_GOST
+               case HashAlgo::GOST:
+                       return new BotanGOSTR3411();
+#endif
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of a MAC algorithm
+MacAlgorithm* BotanCryptoFactory::getMacAlgorithm(MacAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case MacAlgo::HMAC_MD5:
+                       return new BotanHMACMD5();
+               case MacAlgo::HMAC_SHA1:
+                       return new BotanHMACSHA1();
+               case MacAlgo::HMAC_SHA224:
+                       return new BotanHMACSHA224();
+               case MacAlgo::HMAC_SHA256:
+                       return new BotanHMACSHA256();
+               case MacAlgo::HMAC_SHA384:
+                       return new BotanHMACSHA384();
+               case MacAlgo::HMAC_SHA512:
+                       return new BotanHMACSHA512();
+#ifdef WITH_GOST
+               case MacAlgo::HMAC_GOST:
+                       return new BotanHMACGOSTR3411();
+#endif
+               case MacAlgo::CMAC_DES:
+                       return new BotanCMACDES();
+               case MacAlgo::CMAC_AES:
+                       return new BotanCMACAES();
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Get the global RNG (may be an unique RNG per thread)
+RNG* BotanCryptoFactory::getRNG(RNGImpl::Type name /* = RNGImpl::Default */)
+{
+       if (name == RNGImpl::Default)
+       {
+               RNG *threadRNG = NULL;
+
+               // Lock access to the map
+               MutexLocker lock(rngsMutex);
+
+#ifdef HAVE_PTHREAD_H
+               // Get thread ID
+               pthread_t threadID = pthread_self();
+
+               // Find the RNG
+               std::map<pthread_t,RNG*>::iterator findIt;
+               findIt=rngs.find(threadID);
+               if (findIt != rngs.end())
+               {
+                       return findIt->second;
+               }
+
+               threadRNG = new BotanRNG();
+               rngs[threadID] = threadRNG;
+#elif _WIN32
+               // Get thread ID
+               DWORD threadID = GetCurrentThreadId();
+
+               // Find the RNG
+               std::map<DWORD,RNG*>::iterator findIt;
+               findIt=rngs.find(threadID);
+               if (findIt != rngs.end())
+               {
+                       return findIt->second;
+               }
+
+               threadRNG = new BotanRNG();
+               rngs[threadID] = threadRNG;
+#else
+#error "There are no thread-specific data implementations for your operating system yet"
+#endif
+               return threadRNG;
+       }
+       else
+       {
+               // No RNG implementation is available
+               ERROR_MSG("Unknown RNG '%i'", name);
+
+               return NULL;
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h b/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h
new file mode 100644 (file)
index 0000000..df7556d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanCryptoFactory.h
+
+ This is a Botan based cryptographic algorithm factory
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANCRYPTOFACTORY_H
+#define _SOFTHSM_V2_BOTANCRYPTOFACTORY_H
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#include "config.h"
+#include "CryptoFactory.h"
+#include "SymmetricAlgorithm.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "RNG.h"
+#include "MutexFactory.h"
+#include <memory>
+#include <map>
+#include <botan/version.h>
+
+class BotanCryptoFactory : public CryptoFactory
+{
+public:
+       // Return the one-and-only instance
+       static BotanCryptoFactory* i();
+
+       // This will destroy the one-and-only instance.
+       static void reset();
+
+       // Create a concrete instance of a symmetric algorithm
+       SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type algorithm);
+
+       // Create a concrete instance of an asymmetric algorithm
+       AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type algorithm);
+
+       // Create a concrete instance of a hash algorithm
+       HashAlgorithm* getHashAlgorithm(HashAlgo::Type algorithm);
+
+       // Create a concrete instance of a MAC algorithm
+       MacAlgorithm* getMacAlgorithm(MacAlgo::Type algorithm);
+
+       // Get the global RNG (may be an unique RNG per thread)
+       RNG* getRNG(RNGImpl::Type name = RNGImpl::Default);
+
+       // Destructor
+       ~BotanCryptoFactory();
+
+private:
+       // Constructor
+       BotanCryptoFactory();
+
+       // The one-and-only instance
+#ifdef HAVE_CXX11
+       static std::unique_ptr<BotanCryptoFactory> instance;
+#else
+       static std::auto_ptr<BotanCryptoFactory> instance;
+#endif
+
+       // Thread specific RNG
+#ifdef HAVE_PTHREAD_H
+       std::map<pthread_t, RNG*> rngs;
+#elif _WIN32
+       std::map<DWORD, RNG*> rngs;
+#endif
+        Mutex* rngsMutex;
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       bool wasInitialized;
+#endif
+};
+
+#endif // !_SOFTHSM_V2_BOTANCRYPTOFACTORY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDES.cpp b/SoftHSMv2/src/lib/crypto/BotanDES.cpp
new file mode 100644 (file)
index 0000000..393cf4d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDES.cpp
+
+ Botan (3)DES implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanDES.h"
+#include <algorithm>
+#include "odd.h"
+
+bool BotanDES::wrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       ERROR_MSG("DES does not support key wrapping");
+
+       return false;
+}
+
+bool BotanDES::unwrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       ERROR_MSG("DES does not support key unwrapping");
+
+       return false;
+}
+
+std::string BotanDES::getCipher() const
+{
+       std::string algo;
+       std::string mode;
+       std::string padding;
+
+       if (currentKey == NULL) return "";
+
+       // Check currentKey bit length; 3DES only supports 56-bit, 112-bit or 168-bit keys
+       switch (currentKey->getBitLen())
+       {
+               case 56:
+                       // People shouldn't really be using 56-bit DES keys, generate a warning
+                       DEBUG_MSG("CAUTION: use of 56-bit DES keys is not recommended!");
+                       algo = "DES";
+                       break;
+               case 112:
+               case 168:
+                       algo = "TripleDES";
+                       break;
+               default:
+                       ERROR_MSG("Invalid DES currentKey length (%d bits)", currentKey->getBitLen());
+
+                       return "";
+       }
+
+       // Determine the cipher mode
+       switch (currentCipherMode)
+       {
+               case SymMode::CBC:
+                       mode = "CBC";
+                       break;
+               case SymMode::CFB:
+                       mode = "CFB";
+                       break;
+               case SymMode::ECB:
+                       mode = "ECB";
+                       break;
+               case SymMode::OFB:
+                       mode = "OFB";
+                       break;
+               default:
+                       ERROR_MSG("Invalid DES cipher mode %i", currentCipherMode);
+
+                       return "";
+       }
+
+       // Check padding mode
+       if (currentCipherMode == SymMode::OFB ||
+           currentCipherMode == SymMode::CFB)
+       {
+               padding = "";
+       }
+       else if (currentPaddingMode)
+       {
+               padding = "/PKCS7";
+       }
+       else
+       {
+               padding = "/NoPadding";
+       }
+
+       return algo + "/" + mode + padding;
+}
+
+bool BotanDES::generateKey(SymmetricKey& key, RNG* rng /* = NULL */)
+{
+       if (rng == NULL)
+       {
+               return false;
+       }
+
+       if (key.getBitLen() == 0)
+       {
+               return false;
+       }
+
+       ByteString keyBits;
+
+       // don't count parity bit
+       if (!rng->generateRandom(keyBits, key.getBitLen()/7))
+       {
+               return false;
+       }
+
+       // fix the odd parity
+       size_t i;
+       for (i = 0; i < keyBits.size(); i++)
+       {
+               keyBits[i] = odd_parity[keyBits[i]];
+       }
+
+
+       return key.setKeyBits(keyBits);
+}
+
+size_t BotanDES::getBlockSize() const
+{
+       // The block size is 64 bits
+       return 64 >> 3;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDES.h b/SoftHSMv2/src/lib/crypto/BotanDES.h
new file mode 100644 (file)
index 0000000..4f81fe6
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDES.h
+
+ Botan (3)DES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDES_H
+#define _SOFTHSM_V2_BOTANDES_H
+
+#include <string>
+#include "config.h"
+#include "BotanSymmetricAlgorithm.h"
+
+class BotanDES : public BotanSymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~BotanDES() { }
+
+       // Wrap/Unwrap keys
+       virtual bool wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       virtual bool unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       // Generate key
+       virtual bool generateKey(SymmetricKey& key, RNG* rng = NULL);
+
+       // Return the block size
+       virtual size_t getBlockSize() const;
+
+protected:
+       // Return the right Botan cipher for the operation
+       virtual std::string getCipher() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANDES_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDH.cpp b/SoftHSMv2/src/lib/crypto/BotanDH.cpp
new file mode 100644 (file)
index 0000000..5adc239
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDH.cpp
+
+ Botan Diffie-Hellman asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDH.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "DHParameters.h"
+#include "BotanDHKeyPair.h"
+#include "BotanUtil.h"
+#include <algorithm>
+#include <botan/dl_group.h>
+#include <botan/dh.h>
+#include <botan/pubkey.h>
+#include <botan/version.h>
+
+// Signing functions
+bool BotanDH::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                      const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+bool BotanDH::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+bool BotanDH::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+// Verification functions
+bool BotanDH::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                        const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+bool BotanDH::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+bool BotanDH::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool BotanDH::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                     ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DH does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool BotanDH::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                     ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DH does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool BotanDH::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(DHParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for DH key generation");
+
+               return false;
+       }
+
+       DHParameters* params = (DHParameters*) parameters;
+
+       // Generate the key-pair
+       BotanDH_PrivateKey* dh = NULL;
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+
+               // PKCS#3: 2^(l-1) <= x < 2^l
+               Botan::BigInt x;
+               if (params->getXBitLength() > 0)
+               {
+                       x.randomize(*rng->getRNG(), params->getXBitLength());
+               }
+
+               dh = new BotanDH_PrivateKey(*rng->getRNG(),
+                                       Botan::DL_Group(BotanUtil::byteString2bigInt(params->getP()),
+                                       BotanUtil::byteString2bigInt(params->getG())),
+                                       x);
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("DH key generation failed with %s", e.what());
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanDHKeyPair* kp = new BotanDHKeyPair();
+
+       ((BotanDHPublicKey*) kp->getPublicKey())->setFromBotan(dh);
+       ((BotanDHPrivateKey*) kp->getPrivateKey())->setFromBotan(dh);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete dh;
+
+       return true;
+}
+
+bool BotanDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
+{
+       // Check parameters
+       if ((ppSymmetricKey == NULL) ||
+           (publicKey == NULL) ||
+           (privateKey == NULL))
+       {
+               return false;
+       }
+
+       // Get keys
+       Botan::DH_PublicKey* pub = ((BotanDHPublicKey*) publicKey)->getBotanKey();
+       BotanDH_PrivateKey* priv = ((BotanDHPrivateKey*) privateKey)->getBotanKey();
+       if (pub == NULL || priv == NULL || priv->impl == NULL)
+       {
+               ERROR_MSG("Failed to get Botan DH keys");
+
+               return false;
+       }
+
+       // Derive the secret
+       Botan::SymmetricKey sk;
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               Botan::PK_Key_Agreement ka(*priv->impl, *rng->getRNG(), "Raw");
+#else
+               Botan::PK_Key_Agreement ka(*priv->impl, "Raw");
+#endif
+               sk = ka.derive_key(0, pub->public_value());
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Botan DH key agreement failed: %s", e.what());
+
+               return false;
+       }
+
+       ByteString secret;
+
+       // We compensate that Botan removes leading zeros
+       int size = ((BotanDHPublicKey*) publicKey)->getOutputLength();
+       int keySize = sk.length();
+       secret.wipe(size);
+       memcpy(&secret[0] + size - keySize, sk.begin(), keySize);
+
+       *ppSymmetricKey = new SymmetricKey(secret.size() * 8);
+       if (*ppSymmetricKey == NULL)
+       {
+               ERROR_MSG("Can't create DH secret");
+
+               return false;
+       }
+       if (!(*ppSymmetricKey)->setKeyBits(secret))
+       {
+               delete *ppSymmetricKey;
+               *ppSymmetricKey = NULL;
+               return false;
+       }
+
+       return true;
+}
+
+unsigned long BotanDH::getMinKeySize()
+{
+       return 512;
+}
+
+unsigned long BotanDH::getMaxKeySize()
+{
+       return 4096;
+}
+
+bool BotanDH::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
+{
+       if ((ppParams == NULL) || (parameters == NULL))
+       {
+               return false;
+       }
+
+       size_t bitLen = (size_t) parameters;
+
+       if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
+       {
+               ERROR_MSG("This DH key size is not supported");
+
+               return false;
+       }
+
+       Botan::DL_Group* group = NULL;
+       try
+       {
+               BotanRNG* brng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               group = new Botan::DL_Group(*brng->getRNG(), Botan::DL_Group::Strong, bitLen);
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Failed to generate %d bit DH parameters: %s", bitLen, e.what());
+
+               return false;
+       }
+
+       // Store the DH parameters
+       DHParameters* params = new DHParameters();
+
+       ByteString p = BotanUtil::bigInt2ByteString(group->get_p());
+       params->setP(p);
+       ByteString g = BotanUtil::bigInt2ByteString(group->get_g());
+       params->setG(g);
+
+       *ppParams = params;
+
+       delete group;
+
+       return true;
+}
+
+bool BotanDH::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanDHKeyPair* kp = new BotanDHKeyPair();
+
+       bool rv = true;
+
+       if (!((DHPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((DHPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanDH::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanDHPublicKey* pub = new BotanDHPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanDH::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanDHPrivateKey* priv = new BotanDHPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanDH::newPublicKey()
+{
+       return (PublicKey*) new BotanDHPublicKey();
+}
+
+PrivateKey* BotanDH::newPrivateKey()
+{
+       return (PrivateKey*) new BotanDHPrivateKey();
+}
+
+AsymmetricParameters* BotanDH::newParameters()
+{
+       return (AsymmetricParameters*) new DHParameters();
+}
+
+bool BotanDH::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       DHParameters* params = new DHParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDH.h b/SoftHSMv2/src/lib/crypto/BotanDH.h
new file mode 100644 (file)
index 0000000..af2ac59
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDH.h
+
+ Botan Diffie-Hellman asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDH_H
+#define _SOFTHSM_V2_BOTANDH_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanDH : public AsymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~BotanDH() { }
+
+       // Signing functions
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool generateParameters(AsymmetricParameters** ppParams, void* parameters = NULL, RNG* rng = NULL);
+       virtual bool deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_BOTANDH_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp
new file mode 100644 (file)
index 0000000..10c2131
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHKeyPair.cpp
+
+ Botan Diffie-Hellman key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDHKeyPair.h"
+
+// Set the public key
+void BotanDHKeyPair::setPublicKey(BotanDHPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanDHKeyPair::setPrivateKey(BotanDHPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanDHKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanDHKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanDHKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanDHKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h
new file mode 100644 (file)
index 0000000..629c6fd
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHKeyPair.h
+
+ Botan DiffieHellman key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDHKEYPAIR_H
+#define _SOFTHSM_V2_BOTANDHKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanDHPublicKey.h"
+#include "BotanDHPrivateKey.h"
+
+class BotanDHKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanDHPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanDHPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanDHPublicKey pubKey;
+
+       // The private key
+       BotanDHPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANDHKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp
new file mode 100644 (file)
index 0000000..cb7a530
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHPrivateKey.cpp
+
+ Botan Diffie-Hellman private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDHPrivateKey.h"
+#include "BotanCryptoFactory.h"
+#include "BotanRNG.h"
+#include "BotanUtil.h"
+#include <string.h>
+#include <botan/pkcs8.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/oids.h>
+#include <botan/version.h>
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+std::vector<Botan::byte> BotanDH_PrivateKey::public_value() const
+{
+       return impl->public_value();
+}
+#else
+Botan::MemoryVector<Botan::byte> BotanDH_PrivateKey::public_value() const
+{
+       return impl->public_value();
+}
+#endif
+
+// Redefine of DH_PrivateKey constructor with the correct format
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+BotanDH_PrivateKey::BotanDH_PrivateKey(
+                       const Botan::AlgorithmIdentifier& alg_id,
+                       const Botan::secure_vector<Botan::byte>& key_bits,
+                       Botan::RandomNumberGenerator& rng) :
+       Botan::DL_Scheme_PrivateKey(alg_id, key_bits, Botan::DL_Group::PKCS3_DH_PARAMETERS)
+{
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,27)
+       impl = new Botan::DH_PrivateKey(rng, m_group, m_x);
+#else
+       impl = new Botan::DH_PrivateKey(rng, group, x);
+#endif
+}
+#else
+BotanDH_PrivateKey::BotanDH_PrivateKey(
+                       const Botan::AlgorithmIdentifier& alg_id,
+                       const Botan::MemoryRegion<Botan::byte>& key_bits,
+                       Botan::RandomNumberGenerator& rng) :
+       Botan::DL_Scheme_PrivateKey(alg_id, key_bits, Botan::DL_Group::PKCS3_DH_PARAMETERS)
+{
+       impl = new Botan::DH_PrivateKey(rng, group, x);
+}
+#endif
+
+BotanDH_PrivateKey::BotanDH_PrivateKey(Botan::RandomNumberGenerator& rng,
+                                      const Botan::DL_Group& grp,
+                                      const Botan::BigInt& x_arg)
+{
+       impl = new Botan::DH_PrivateKey(rng, grp, x_arg);
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,27)
+       m_group = grp;
+       m_x = x_arg;
+       m_y = impl->get_y();
+#else
+       group = grp;
+       x = x_arg;
+       y = impl->get_y();
+#endif
+}
+
+BotanDH_PrivateKey::~BotanDH_PrivateKey()
+{
+       delete impl;
+}
+
+// Constructors
+BotanDHPrivateKey::BotanDHPrivateKey()
+{
+       dh = NULL;
+}
+
+BotanDHPrivateKey::BotanDHPrivateKey(const BotanDH_PrivateKey* inDH)
+{
+       dh = NULL;
+
+       setFromBotan(inDH);
+}
+
+// Destructor
+BotanDHPrivateKey::~BotanDHPrivateKey()
+{
+       delete dh;
+}
+
+// The type
+/*static*/ const char* BotanDHPrivateKey::type = "Botan DH Private Key";
+
+// Set from Botan representation
+void BotanDHPrivateKey::setFromBotan(const BotanDH_PrivateKey* inDH)
+{
+       ByteString inP = BotanUtil::bigInt2ByteString(inDH->impl->group_p());
+       setP(inP);
+       ByteString inG = BotanUtil::bigInt2ByteString(inDH->impl->group_g());
+       setG(inG);
+       ByteString inX = BotanUtil::bigInt2ByteString(inDH->impl->get_x());
+       setX(inX);
+}
+
+// Check if the key is of the given type
+bool BotanDHPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DH private key components
+void BotanDHPrivateKey::setX(const ByteString& inX)
+{
+       DHPrivateKey::setX(inX);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+// Setters for the DH public key components
+void BotanDHPrivateKey::setP(const ByteString& inP)
+{
+       DHPrivateKey::setP(inP);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+void BotanDHPrivateKey::setG(const ByteString& inG)
+{
+       DHPrivateKey::setG(inG);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanDHPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       createBotanKey();
+       if (dh == NULL) return der;
+       // Force PKCS3_DH_PARAMETERS for p, g and no q.
+       const size_t PKCS8_VERSION = 0;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+       const std::vector<Botan::byte> parameters = dh->impl->get_domain().DER_encode(Botan::DL_Group::PKCS3_DH_PARAMETERS);
+       const Botan::AlgorithmIdentifier alg_id(dh->impl->get_oid(), parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(dh->impl->private_key_bits(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       const std::vector<Botan::byte> parameters = dh->impl->get_domain().DER_encode(Botan::DL_Group::PKCS3_DH_PARAMETERS);
+       const Botan::AlgorithmIdentifier alg_id(dh->impl->get_oid(), parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(dh->impl->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#else
+       const Botan::MemoryVector<Botan::byte> parameters = dh->impl->get_domain().DER_encode(Botan::DL_Group::PKCS3_DH_PARAMETERS);
+       const Botan::AlgorithmIdentifier alg_id(dh->impl->get_oid(), parameters);
+       const Botan::SecureVector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(dh->impl->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#endif
+       der.resize(ber.size());
+       memcpy(&der[0], &ber[0], ber.size());
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanDHPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
+       if (source.end_of_data()) return false;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> keydata;
+#else
+       Botan::SecureVector<Botan::byte> keydata;
+#endif
+       Botan::AlgorithmIdentifier alg_id;
+       BotanDH_PrivateKey* key = NULL;
+       try
+       {
+               Botan::BER_Decoder(source)
+               .start_cons(Botan::SEQUENCE)
+                       .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+                       .decode(alg_id)
+                       .decode(keydata, Botan::OCTET_STRING)
+                       .discard_remaining()
+               .end_cons();
+               if (keydata.empty())
+                       throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
+               if (Botan::OIDS::lookup(alg_id.oid).compare("DH"))
+               {
+                       ERROR_MSG("Decoded private key not DH");
+
+                       return false;
+               }
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               key = new BotanDH_PrivateKey(alg_id, keydata, *rng->getRNG());
+               if (key == NULL) return false;
+
+               setFromBotan(key);
+
+               delete key;
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Decode failed on %s", e.what());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+BotanDH_PrivateKey* BotanDHPrivateKey::getBotanKey()
+{
+       if (!dh)
+       {
+               createBotanKey();
+       }
+
+       return dh;
+}
+
+// Create the Botan representation of the key
+void BotanDHPrivateKey::createBotanKey()
+{
+       // y is not needed
+       if (p.size() != 0 &&
+           g.size() != 0 &&
+           x.size() != 0)
+       {
+               if (dh)
+               {
+                       delete dh;
+                       dh = NULL;
+               }
+
+               try
+               {
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       dh = new BotanDH_PrivateKey(*rng->getRNG(),
+                               Botan::DL_Group(BotanUtil::byteString2bigInt(p),
+                                               BotanUtil::byteString2bigInt(g)),
+                               BotanUtil::byteString2bigInt(x));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h
new file mode 100644 (file)
index 0000000..5991c21
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHPrivateKey.h
+
+ Botan Diffie-Hellman private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDHPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANDHPRIVATEKEY_H
+
+#include "config.h"
+#include "DHPrivateKey.h"
+#include <botan/dh.h>
+#include <botan/version.h>
+
+// Derived from the DH_PrivateKey class
+class BotanDH_PrivateKey : public Botan::DH_PublicKey,
+                          public virtual Botan::DL_Scheme_PrivateKey
+{
+public:
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> public_value() const;
+#else
+       Botan::MemoryVector<Botan::byte> public_value() const;
+#endif
+
+       // Constructors
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       BotanDH_PrivateKey(const Botan::AlgorithmIdentifier& alg_id,
+                          const Botan::secure_vector<Botan::byte>& key_bits,
+                          Botan::RandomNumberGenerator& rng);
+#else
+       BotanDH_PrivateKey(const Botan::AlgorithmIdentifier& alg_id,
+                          const Botan::MemoryRegion<Botan::byte>& key_bits,
+                          Botan::RandomNumberGenerator& rng);
+#endif
+
+       BotanDH_PrivateKey(Botan::RandomNumberGenerator& rng,
+                          const Botan::DL_Group& grp,
+                          const Botan::BigInt& x = 0);
+
+       ~BotanDH_PrivateKey();
+
+       Botan::DH_PrivateKey* impl;
+};
+
+class BotanDHPrivateKey : public DHPrivateKey
+{
+public:
+       // Constructors
+       BotanDHPrivateKey();
+
+       BotanDHPrivateKey(const BotanDH_PrivateKey* inDH);
+
+       // Destructor
+       virtual ~BotanDHPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DH private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const BotanDH_PrivateKey* inDH);
+
+       // Retrieve the Botan representation of the key
+       BotanDH_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       BotanDH_PrivateKey* dh;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANDHPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp
new file mode 100644 (file)
index 0000000..16c4b12
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHPublicKey.cpp
+
+ Botan Diffie-Hellman public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDHPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanDHPublicKey::BotanDHPublicKey()
+{
+       dh = NULL;
+}
+
+BotanDHPublicKey::BotanDHPublicKey(const Botan::DH_PublicKey* inDH)
+{
+       dh = NULL;
+
+       setFromBotan(inDH);
+}
+
+// Destructor
+BotanDHPublicKey::~BotanDHPublicKey()
+{
+       delete dh;
+}
+
+// The type
+/*static*/ const char* BotanDHPublicKey::type = "Botan DH Public Key";
+
+// Set from Botan representation
+void BotanDHPublicKey::setFromBotan(const Botan::DH_PublicKey* inDH)
+{
+       ByteString inP = BotanUtil::bigInt2ByteString(inDH->group_p());
+       setP(inP);
+       ByteString inG = BotanUtil::bigInt2ByteString(inDH->group_g());
+       setG(inG);
+       ByteString inY = BotanUtil::bigInt2ByteString(inDH->get_y());
+       setY(inY);
+}
+
+// Check if the key is of the given type
+bool BotanDHPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DH public key components
+void BotanDHPublicKey::setP(const ByteString& inP)
+{
+       DHPublicKey::setP(inP);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+void BotanDHPublicKey::setG(const ByteString& inG)
+{
+       DHPublicKey::setG(inG);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+void BotanDHPublicKey::setY(const ByteString& inY)
+{
+       DHPublicKey::setY(inY);
+
+       if (dh)
+       {
+               delete dh;
+               dh = NULL;
+       }
+}
+
+// Retrieve the Botan representation of the key
+Botan::DH_PublicKey* BotanDHPublicKey::getBotanKey()
+{
+       if (!dh)
+       {
+               createBotanKey();
+       }
+
+       return dh;
+}
+
+// Create the Botan representation of the key
+void BotanDHPublicKey::createBotanKey()
+{
+       // We actually do not need to check q, since it can be set zero
+       if (p.size() != 0 && y.size() != 0)
+       {
+               if (dh)
+               {
+                       delete dh;
+                       dh = NULL;
+               }
+
+               try
+               {
+                       dh = new Botan::DH_PublicKey(Botan::DL_Group(BotanUtil::byteString2bigInt(p),
+                                                       BotanUtil::byteString2bigInt(g)),
+                                                       BotanUtil::byteString2bigInt(y));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h
new file mode 100644 (file)
index 0000000..66e90c2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDHPublicKey.h
+
+ Botan Diffie-Hellman public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDHPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANDHPUBLICKEY_H
+
+#include "config.h"
+#include "DHPublicKey.h"
+#include <botan/dh.h>
+
+class BotanDHPublicKey : public DHPublicKey
+{
+public:
+       // Constructors
+       BotanDHPublicKey();
+
+       BotanDHPublicKey(const Botan::DH_PublicKey* inDH);
+
+       // Destructor
+       virtual ~BotanDHPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::DH_PublicKey* inDH);
+
+       // Retrieve the Botan representation of the key
+       Botan::DH_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::DH_PublicKey* dh;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANDHPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSA.cpp b/SoftHSMv2/src/lib/crypto/BotanDSA.cpp
new file mode 100644 (file)
index 0000000..ab3aa01
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSA.cpp
+
+ Botan DSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDSA.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "DSAParameters.h"
+#include "BotanDSAKeyPair.h"
+#include "BotanUtil.h"
+#include <algorithm>
+#include <botan/dl_group.h>
+#include <botan/dsa.h>
+#include <botan/version.h>
+#include <iostream>
+
+// Constructor
+BotanDSA::BotanDSA()
+{
+       signer = NULL;
+       verifier = NULL;
+}
+
+// Destructor
+BotanDSA::~BotanDSA()
+{
+       delete signer;
+       delete verifier;
+}
+
+// Signing functions
+bool BotanDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                   ByteString& signature, const AsymMech::Type mechanism,
+                   const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       std::string emsa;
+
+       if (mechanism == AsymMech::DSA)
+       {
+               emsa = "Raw";
+       }
+       else
+        {
+               // Call default implementation
+               return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+        }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanDSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+        BotanDSAPrivateKey* pk = (BotanDSAPrivateKey*) privateKey;
+        Botan::DSA_PrivateKey* botanKey = pk->getBotanKey();
+
+        if (!botanKey)
+        {
+               ERROR_MSG("Could not get the Botan private key");
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+bool BotanDSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                       const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanDSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+
+       switch (mechanism)
+       {
+               case AsymMech::DSA_SHA1:
+                       emsa = "EMSA1(SHA-160)";
+                       break;
+               case AsymMech::DSA_SHA224:
+                       emsa = "EMSA1(SHA-224)";
+                       break;
+               case AsymMech::DSA_SHA256:
+                       emsa = "EMSA1(SHA-256)";
+                       break;
+               case AsymMech::DSA_SHA384:
+                       emsa = "EMSA1(SHA-384)";
+                       break;
+               case AsymMech::DSA_SHA512:
+                       emsa = "EMSA1(SHA-512)";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+        }
+
+        BotanDSAPrivateKey* pk = (BotanDSAPrivateKey*) currentPrivateKey;
+        Botan::DSA_PrivateKey* botanKey = pk->getBotanKey();
+
+        if (!botanKey)
+        {
+               ERROR_MSG("Could not get the Botan private key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanDSA::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (dataToSign.size() != 0)
+               {
+                       signer->update(dataToSign.const_byte_str(),
+                                      dataToSign.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanDSA::signFinal(ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->signature(*rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool BotanDSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                     const ByteString& signature, const AsymMech::Type mechanism,
+                     const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       std::string emsa;
+
+       if (mechanism == AsymMech::DSA)
+       {
+               emsa = "Raw";
+       }
+        else
+        {
+               // Call the generic function
+               return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanDSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       BotanDSAPublicKey* pk = (BotanDSAPublicKey*) publicKey;
+       Botan::DSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->verify_message(originalData.const_byte_str(),
+                                                       originalData.size(),
+                                                       signature.const_byte_str(),
+                                                       signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+bool BotanDSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                         const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanDSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+
+       switch (mechanism)
+       {
+               case AsymMech::DSA_SHA1:
+                       emsa = "EMSA1(SHA-160)";
+                       break;
+               case AsymMech::DSA_SHA224:
+                       emsa = "EMSA1(SHA-224)";
+                       break;
+               case AsymMech::DSA_SHA256:
+                       emsa = "EMSA1(SHA-256)";
+                       break;
+               case AsymMech::DSA_SHA384:
+                       emsa = "EMSA1(SHA-384)";
+                       break;
+               case AsymMech::DSA_SHA512:
+                       emsa = "EMSA1(SHA-512)";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+        }
+
+       BotanDSAPublicKey* pk = (BotanDSAPublicKey*) currentPublicKey;
+       Botan::DSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanDSA::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (originalData.size() != 0)
+               {
+                       verifier->update(originalData.const_byte_str(),
+                                        originalData.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanDSA::verifyFinal(const ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->check_signature(signature.const_byte_str(), signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+// Encryption functions
+bool BotanDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                      ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DSA does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool BotanDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                      ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DSA does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool BotanDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(DSAParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for DSA key generation");
+
+               return false;
+       }
+
+       DSAParameters* params = (DSAParameters*) parameters;
+
+       // Generate the key-pair
+       Botan::DSA_PrivateKey* dsa = NULL;
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               dsa = new Botan::DSA_PrivateKey(*rng->getRNG(),
+                                       Botan::DL_Group(BotanUtil::byteString2bigInt(params->getP()),
+                                       BotanUtil::byteString2bigInt(params->getQ()),
+                                       BotanUtil::byteString2bigInt(params->getG())));
+       }
+       catch (...)
+       {
+               ERROR_MSG("DSA key generation failed");
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanDSAKeyPair* kp = new BotanDSAKeyPair();
+
+       ((BotanDSAPublicKey*) kp->getPublicKey())->setFromBotan(dsa);
+       ((BotanDSAPrivateKey*) kp->getPrivateKey())->setFromBotan(dsa);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete dsa;
+
+       return true;
+}
+
+unsigned long BotanDSA::getMinKeySize()
+{
+       return 512;
+}
+
+unsigned long BotanDSA::getMaxKeySize()
+{
+       // Taken from OpenSSL
+       return 10000;
+}
+
+bool BotanDSA::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
+{
+       if ((ppParams == NULL) || (parameters == NULL))
+       {
+               return false;
+       }
+
+       size_t bitLen = (size_t) parameters;
+
+       if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
+       {
+               ERROR_MSG("This DSA key size is not supported");
+
+               return false;
+       }
+
+       Botan::DL_Group* group = NULL;
+       // Taken from OpenSSL
+       size_t qLen = bitLen >= 2048 ? 256 : 160;
+       try
+       {
+               BotanRNG* brng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               group = new Botan::DL_Group(*brng->getRNG(), Botan::DL_Group::Prime_Subgroup, bitLen, qLen);
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Failed to generate %d bit DSA parameters: %s", bitLen, e.what());
+
+               return false;
+       }
+
+       // Store the DSA parameters
+       DSAParameters* params = new DSAParameters();
+
+       ByteString p = BotanUtil::bigInt2ByteString(group->get_p());
+       params->setP(p);
+       ByteString q = BotanUtil::bigInt2ByteString(group->get_q());
+       params->setQ(q);
+       ByteString g = BotanUtil::bigInt2ByteString(group->get_g());
+       params->setG(g);
+
+       *ppParams = params;
+
+       delete group;
+
+       return true;
+}
+
+bool BotanDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanDSAKeyPair* kp = new BotanDSAKeyPair();
+
+       bool rv = true;
+
+       if (!((DSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((DSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanDSAPublicKey* pub = new BotanDSAPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanDSAPrivateKey* priv = new BotanDSAPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanDSA::newPublicKey()
+{
+       return (PublicKey*) new BotanDSAPublicKey();
+}
+
+PrivateKey* BotanDSA::newPrivateKey()
+{
+       return (PrivateKey*) new BotanDSAPrivateKey();
+}
+
+AsymmetricParameters* BotanDSA::newParameters()
+{
+       return (AsymmetricParameters*) new DSAParameters();
+}
+
+bool BotanDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       DSAParameters* params = new DSAParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSA.h b/SoftHSMv2/src/lib/crypto/BotanDSA.h
new file mode 100644 (file)
index 0000000..dd10016
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSA.h
+
+ Botan DSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDSA_H
+#define _SOFTHSM_V2_BOTANDSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanDSA : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       BotanDSA();
+
+       // Destructor
+       virtual ~BotanDSA();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool generateParameters(AsymmetricParameters** ppParams, void* parameters = NULL, RNG* rng = NULL);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       Botan::PK_Signer* signer;
+       Botan::PK_Verifier* verifier;
+};
+
+#endif // !_SOFTHSM_V2_BOTANDSA_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp
new file mode 100644 (file)
index 0000000..9d98125
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAKeyPair.cpp
+
+ Botan DSA key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDSAKeyPair.h"
+
+// Set the public key
+void BotanDSAKeyPair::setPublicKey(BotanDSAPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanDSAKeyPair::setPrivateKey(BotanDSAPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanDSAKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanDSAKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanDSAKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanDSAKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h
new file mode 100644 (file)
index 0000000..beb07e1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAKeyPair.h
+
+ Botan DSA key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDSAKEYPAIR_H
+#define _SOFTHSM_V2_BOTANDSAKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanDSAPublicKey.h"
+#include "BotanDSAPrivateKey.h"
+
+class BotanDSAKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanDSAPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanDSAPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanDSAPublicKey pubKey;
+
+       // The private key
+       BotanDSAPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANDSAKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..a7f1c9b
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAPrivateKey.cpp
+
+ Botan DSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDSAPrivateKey.h"
+#include "BotanCryptoFactory.h"
+#include "BotanRNG.h"
+#include "BotanUtil.h"
+#include <string.h>
+#include <botan/pkcs8.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/oids.h>
+#include <botan/version.h>
+
+// Constructors
+BotanDSAPrivateKey::BotanDSAPrivateKey()
+{
+       dsa = NULL;
+}
+
+BotanDSAPrivateKey::BotanDSAPrivateKey(const Botan::DSA_PrivateKey* inDSA)
+{
+       dsa = NULL;
+
+       setFromBotan(inDSA);
+}
+
+// Destructor
+BotanDSAPrivateKey::~BotanDSAPrivateKey()
+{
+       delete dsa;
+}
+
+// The type
+/*static*/ const char* BotanDSAPrivateKey::type = "Botan DSA Private Key";
+
+// Set from Botan representation
+void BotanDSAPrivateKey::setFromBotan(const Botan::DSA_PrivateKey* inDSA)
+{
+       ByteString inP = BotanUtil::bigInt2ByteString(inDSA->group_p());
+       setP(inP);
+       ByteString inQ = BotanUtil::bigInt2ByteString(inDSA->group_q());
+       setQ(inQ);
+       ByteString inG = BotanUtil::bigInt2ByteString(inDSA->group_g());
+       setG(inG);
+       ByteString inX = BotanUtil::bigInt2ByteString(inDSA->get_x());
+       setX(inX);
+}
+
+// Check if the key is of the given type
+bool BotanDSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DSA private key components
+void BotanDSAPrivateKey::setX(const ByteString& inX)
+{
+       DSAPrivateKey::setX(inX);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+
+// Setters for the DSA domain parameters
+void BotanDSAPrivateKey::setP(const ByteString& inP)
+{
+       DSAPrivateKey::setP(inP);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+void BotanDSAPrivateKey::setQ(const ByteString& inQ)
+{
+       DSAPrivateKey::setQ(inQ);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+void BotanDSAPrivateKey::setG(const ByteString& inG)
+{
+       DSAPrivateKey::setG(inG);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanDSAPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       createBotanKey();
+       if (dsa == NULL) return der;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       const Botan::secure_vector<Botan::byte> ber = Botan::PKCS8::BER_encode(*dsa);
+#else
+       const Botan::SecureVector<Botan::byte> ber = Botan::PKCS8::BER_encode(*dsa);
+#endif
+       der.resize(ber.size());
+       memcpy(&der[0], &ber[0], ber.size());
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanDSAPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
+       if (source.end_of_data()) return false;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> keydata;
+#else
+       Botan::SecureVector<Botan::byte> keydata;
+#endif
+       Botan::AlgorithmIdentifier alg_id;
+       Botan::DSA_PrivateKey* key = NULL;
+       try
+       {
+
+               Botan::BER_Decoder(source)
+               .start_cons(Botan::SEQUENCE)
+                       .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+                       .decode(alg_id)
+                       .decode(keydata, Botan::OCTET_STRING)
+                       .discard_remaining()
+               .end_cons();
+               if (keydata.empty())
+                       throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
+               if (Botan::OIDS::lookup(alg_id.oid).compare("DSA"))
+               {
+                       ERROR_MSG("Decoded private key not DSA");
+
+                       return false;
+               }
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+               key = new Botan::DSA_PrivateKey(alg_id, keydata);
+#else
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               key = new Botan::DSA_PrivateKey(alg_id, keydata, *rng->getRNG());
+#endif
+               if (key == NULL) return false;
+
+               setFromBotan(key);
+
+               delete key;
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Decode failed on %s", e.what());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+Botan::DSA_PrivateKey* BotanDSAPrivateKey::getBotanKey()
+{
+       if (!dsa)
+       {
+               createBotanKey();
+       }
+
+       return dsa;
+}
+
+// Create the Botan representation of the key
+void BotanDSAPrivateKey::createBotanKey()
+{
+       // y is not needed
+       // Todo: Either q or x is needed. Both is not needed
+       if (p.size() != 0 &&
+           q.size() != 0 &&
+           g.size() != 0 &&
+           x.size() != 0)
+       {
+               if (dsa)
+               {
+                       delete dsa;
+                       dsa = NULL;
+               }
+
+               try
+               {
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       dsa = new Botan::DSA_PrivateKey(*rng->getRNG(),
+                                                       Botan::DL_Group(BotanUtil::byteString2bigInt(p),
+                                                       BotanUtil::byteString2bigInt(q),
+                                                       BotanUtil::byteString2bigInt(g)),
+                                                       BotanUtil::byteString2bigInt(x));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan private key");
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h
new file mode 100644 (file)
index 0000000..5594967
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAPrivateKey.h
+
+ Botan DSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDSAPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANDSAPRIVATEKEY_H
+
+#include "config.h"
+#include "DSAPrivateKey.h"
+#include <botan/dsa.h>
+
+class BotanDSAPrivateKey : public DSAPrivateKey
+{
+public:
+       // Constructors
+       BotanDSAPrivateKey();
+
+       BotanDSAPrivateKey(const Botan::DSA_PrivateKey* inDSA);
+
+       // Destructor
+       virtual ~BotanDSAPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DSA private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DSA domain parameters
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::DSA_PrivateKey* inDSA);
+
+       // Retrieve the Botan representation of the key
+       Botan::DSA_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::DSA_PrivateKey* dsa;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANDSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..a1593d6
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAPublicKey.cpp
+
+ Botan DSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanDSAPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanDSAPublicKey::BotanDSAPublicKey()
+{
+       dsa = NULL;
+}
+
+BotanDSAPublicKey::BotanDSAPublicKey(const Botan::DSA_PublicKey* inDSA)
+{
+       dsa = NULL;
+
+       setFromBotan(inDSA);
+}
+
+// Destructor
+BotanDSAPublicKey::~BotanDSAPublicKey()
+{
+       delete dsa;
+}
+
+// The type
+/*static*/ const char* BotanDSAPublicKey::type = "Botan DSA Public Key";
+
+// Set from Botan representation
+void BotanDSAPublicKey::setFromBotan(const Botan::DSA_PublicKey* inDSA)
+{
+       ByteString inP = BotanUtil::bigInt2ByteString(inDSA->group_p());
+       setP(inP);
+       ByteString inQ = BotanUtil::bigInt2ByteString(inDSA->group_q());
+       setQ(inQ);
+       ByteString inG = BotanUtil::bigInt2ByteString(inDSA->group_g());
+       setG(inG);
+       ByteString inY = BotanUtil::bigInt2ByteString(inDSA->get_y());
+       setY(inY);
+}
+
+// Check if the key is of the given type
+bool BotanDSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DSA public key components
+void BotanDSAPublicKey::setP(const ByteString& inP)
+{
+       DSAPublicKey::setP(inP);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+void BotanDSAPublicKey::setQ(const ByteString& inQ)
+{
+       DSAPublicKey::setQ(inQ);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+void BotanDSAPublicKey::setG(const ByteString& inG)
+{
+       DSAPublicKey::setG(inG);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+void BotanDSAPublicKey::setY(const ByteString& inY)
+{
+       DSAPublicKey::setY(inY);
+
+       if (dsa)
+       {
+               delete dsa;
+               dsa = NULL;
+       }
+}
+
+// Retrieve the Botan representation of the key
+Botan::DSA_PublicKey* BotanDSAPublicKey::getBotanKey()
+{
+       if (!dsa)
+       {
+               createBotanKey();
+       }
+
+       return dsa;
+}
+
+// Create the Botan representation of the key
+void BotanDSAPublicKey::createBotanKey()
+{
+       // We actually do not need to check q, since it can be set zero
+       if (p.size() != 0 &&
+           g.size() != 0 &&
+           y.size() != 0)
+       {
+               if (dsa)
+               {
+                       delete dsa;
+                       dsa = NULL;
+               }
+
+               try
+               {
+                       dsa = new Botan::DSA_PublicKey(Botan::DL_Group(BotanUtil::byteString2bigInt(p),
+                                                       BotanUtil::byteString2bigInt(q),
+                                                       BotanUtil::byteString2bigInt(g)),
+                                                       BotanUtil::byteString2bigInt(y));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h
new file mode 100644 (file)
index 0000000..e4d683d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanDSAPublicKey.h
+
+ Botan DSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANDSAPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANDSAPUBLICKEY_H
+
+#include "config.h"
+#include "DSAPublicKey.h"
+#include <botan/dsa.h>
+
+class BotanDSAPublicKey : public DSAPublicKey
+{
+public:
+       // Constructors
+       BotanDSAPublicKey();
+
+       BotanDSAPublicKey(const Botan::DSA_PublicKey* inDSA);
+
+       // Destructor
+       virtual ~BotanDSAPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DSA public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::DSA_PublicKey* inDSA);
+
+       // Retrieve the Botan representation of the key
+       Botan::DSA_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::DSA_PublicKey* dsa;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANDSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDH.cpp b/SoftHSMv2/src/lib/crypto/BotanECDH.cpp
new file mode 100644 (file)
index 0000000..2741734
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDH.cpp
+
+ Botan ECDH asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDH.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "ECParameters.h"
+#include "BotanECDHKeyPair.h"
+#include "BotanUtil.h"
+#include <algorithm>
+#include <botan/dl_group.h>
+#include <botan/ecdh.h>
+#include <botan/pubkey.h>
+#include <botan/version.h>
+
+// Signing functions
+bool BotanECDH::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                        const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+bool BotanECDH::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+bool BotanECDH::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+// Verification functions
+bool BotanECDH::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                          const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+bool BotanECDH::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+bool BotanECDH::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool BotanECDH::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                       ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDH does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool BotanECDH::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                       ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDH does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool BotanECDH::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for ECDH key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+
+       // Generate the key-pair
+       Botan::ECDH_PrivateKey* eckp = NULL;
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               eckp = new Botan::ECDH_PrivateKey(*rng->getRNG(), BotanUtil::byteString2ECGroup(params->getEC()));
+       }
+       catch (...)
+       {
+               ERROR_MSG("ECDH key generation failed");
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanECDHKeyPair* kp = new BotanECDHKeyPair();
+
+       ((BotanECDHPublicKey*) kp->getPublicKey())->setFromBotan(eckp);
+       ((BotanECDHPrivateKey*) kp->getPrivateKey())->setFromBotan(eckp);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete eckp;
+
+       return true;
+}
+
+bool BotanECDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
+{
+       // Check parameters
+       if ((ppSymmetricKey == NULL) ||
+           (publicKey == NULL) ||
+           (privateKey == NULL))
+       {
+               return false;
+       }
+
+       // Get keys
+       Botan::ECDH_PublicKey* pub = ((BotanECDHPublicKey*) publicKey)->getBotanKey();
+       Botan::ECDH_PrivateKey* priv = ((BotanECDHPrivateKey*) privateKey)->getBotanKey();
+       if (pub == NULL || priv == NULL)
+       {
+               ERROR_MSG("Failed to get Botan ECDH keys");
+
+               return false;
+       }
+
+       // Derive the secret
+       Botan::SymmetricKey sk;
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               Botan::PK_Key_Agreement ka(*priv, *rng->getRNG(), "Raw");
+#else
+               Botan::PK_Key_Agreement ka(*priv, "Raw");
+#endif
+               sk = ka.derive_key(0, pub->public_value());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Botan ECDH key agreement failed");
+
+               return false;
+       }
+
+       ByteString secret;
+
+       // We compensate that Botan removes leading zeros
+       int size = ((BotanECDHPublicKey *)publicKey)->getOrderLength();
+       int keySize = sk.length();
+       secret.wipe(size);
+       memcpy(&secret[0] + size - keySize, sk.begin(), keySize);
+
+       *ppSymmetricKey = new SymmetricKey(secret.size() * 8);
+       if (*ppSymmetricKey == NULL)
+       {
+               ERROR_MSG("Can't create ECDH secret");
+
+               return false;
+       }
+       if (!(*ppSymmetricKey)->setKeyBits(secret))
+       {
+               delete *ppSymmetricKey;
+               *ppSymmetricKey = NULL;
+               return false;
+       }
+
+       return true;
+}
+
+unsigned long BotanECDH::getMinKeySize()
+{
+       // Smallest EC group is secp112r1
+       return 112;
+}
+
+unsigned long BotanECDH::getMaxKeySize()
+{
+       // Biggest EC group is secp521r1
+       return 521;
+}
+
+bool BotanECDH::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanECDHKeyPair* kp = new BotanECDHKeyPair();
+
+       bool rv = true;
+
+       if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanECDH::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanECDHPublicKey* pub = new BotanECDHPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanECDH::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanECDHPrivateKey* priv = new BotanECDHPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanECDH::newPublicKey()
+{
+       return (PublicKey*) new BotanECDHPublicKey();
+}
+
+PrivateKey* BotanECDH::newPrivateKey()
+{
+       return (PrivateKey*) new BotanECDHPrivateKey();
+}
+
+AsymmetricParameters* BotanECDH::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool BotanECDH::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDH.h b/SoftHSMv2/src/lib/crypto/BotanECDH.h
new file mode 100644 (file)
index 0000000..3fac507
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDH.h
+
+ Botan ECDH asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDH_H
+#define _SOFTHSM_V2_BOTANECDH_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanECDH : public AsymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~BotanECDH() { }
+
+       // Signing functions
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDH_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp
new file mode 100644 (file)
index 0000000..74313d9
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHKeyPair.cpp
+
+ Botan ECDH key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDHKeyPair.h"
+
+// Set the public key
+void BotanECDHKeyPair::setPublicKey(BotanECDHPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanECDHKeyPair::setPrivateKey(BotanECDHPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanECDHKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanECDHKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanECDHKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanECDHKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h
new file mode 100644 (file)
index 0000000..a9786b9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHKeyPair.h
+
+ Botan ECDH key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDHKEYPAIR_H
+#define _SOFTHSM_V2_BOTANECDHKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanECDHPublicKey.h"
+#include "BotanECDHPrivateKey.h"
+
+class BotanECDHKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanECDHPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanECDHPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanECDHPublicKey pubKey;
+
+       // The private key
+       BotanECDHPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDHKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp
new file mode 100644 (file)
index 0000000..043e6e1
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHPrivateKey.cpp
+
+ Botan ECDH private key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDHPrivateKey.h"
+#include "BotanCryptoFactory.h"
+#include "BotanRNG.h"
+#include "BotanUtil.h"
+#include <string.h>
+#include <botan/pkcs8.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/asn1_oid.h>
+#include <botan/oids.h>
+#include <botan/version.h>
+
+// Constructors
+BotanECDHPrivateKey::BotanECDHPrivateKey()
+{
+       eckey = NULL;
+}
+
+BotanECDHPrivateKey::BotanECDHPrivateKey(const Botan::ECDH_PrivateKey* inECKEY)
+{
+       eckey = NULL;
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanECDHPrivateKey::~BotanECDHPrivateKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanECDHPrivateKey::type = "Botan ECDH Private Key";
+
+// Get the base point order length
+unsigned long BotanECDHPrivateKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Set from Botan representation
+void BotanECDHPrivateKey::setFromBotan(const Botan::ECDH_PrivateKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+       ByteString inD = BotanUtil::bigInt2ByteString(inECKEY->private_value());
+       setD(inD);
+}
+
+// Check if the key is of the given type
+bool BotanECDHPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the ECDH private key components
+void BotanECDHPrivateKey::setD(const ByteString& inD)
+{
+       ECPrivateKey::setD(inD);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Setters for the ECDH public key components
+void BotanECDHPrivateKey::setEC(const ByteString& inEC)
+{
+       ECPrivateKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanECDHPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       createBotanKey();
+       if (eckey == NULL) return der;
+       const size_t PKCS8_VERSION = 0;
+       // No OID for ECDH
+       const Botan::OID oid("1.2.840.10045.2.1");
+       // Force EC_DOMPAR_ENC_OID
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+       const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(oid, parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->private_key_bits(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(oid, parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#else
+       const Botan::MemoryVector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(oid, parameters);
+       const Botan::SecureVector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#endif
+       der.resize(ber.size());
+       memcpy(&der[0], &ber[0], ber.size());
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanECDHPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
+       if (source.end_of_data()) return false;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> keydata;
+#else
+       Botan::SecureVector<Botan::byte> keydata;
+#endif
+       Botan::AlgorithmIdentifier alg_id;
+       const Botan::OID oid("1.2.840.10045.2.1");
+       Botan::ECDH_PrivateKey* key = NULL;
+       try
+       {
+               Botan::BER_Decoder(source)
+               .start_cons(Botan::SEQUENCE)
+                       .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+                       .decode(alg_id)
+                       .decode(keydata, Botan::OCTET_STRING)
+                       .discard_remaining()
+               .end_cons();
+               if (keydata.empty())
+                       throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
+               // Botan defines == but not != ?!
+               if (!(alg_id.oid == oid))
+               {
+                       ERROR_MSG("Decoded private key not ECDH");
+
+                       return false;
+               }
+               key = new Botan::ECDH_PrivateKey(alg_id, keydata);
+               if (key == NULL) return false;
+
+               setFromBotan(key);
+
+               delete key;
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Decode failed on %s", e.what());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+Botan::ECDH_PrivateKey* BotanECDHPrivateKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+
+// Create the Botan representation of the key
+void BotanECDHPrivateKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           d.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       eckey = new Botan::ECDH_PrivateKey(*rng->getRNG(),
+                                                       group,
+                                                       BotanUtil::byteString2bigInt(d));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h
new file mode 100644 (file)
index 0000000..d84e046
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHPrivateKey.h
+
+ Botan ECDH private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDHPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANECDHPRIVATEKEY_H
+
+#include "config.h"
+#include "ECPrivateKey.h"
+#include <botan/ecdh.h>
+
+class BotanECDHPrivateKey : public ECPrivateKey
+{
+public:
+       // Constructors
+       BotanECDHPrivateKey();
+
+       BotanECDHPrivateKey(const Botan::ECDH_PrivateKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanECDHPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the ECDH private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the ECDH public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::ECDH_PrivateKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::ECDH_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::ECDH_PrivateKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDHPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp
new file mode 100644 (file)
index 0000000..6201f18
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHPublicKey.cpp
+
+ Botan ECDH public key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDHPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanECDHPublicKey::BotanECDHPublicKey()
+{
+       eckey = NULL;
+}
+
+BotanECDHPublicKey::BotanECDHPublicKey(const Botan::ECDH_PublicKey* inECKEY)
+{
+       eckey = NULL;
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanECDHPublicKey::~BotanECDHPublicKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanECDHPublicKey::type = "Botan ECDH Public Key";
+
+// Get the base point order length
+unsigned long BotanECDHPublicKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Set from Botan representation
+void BotanECDHPublicKey::setFromBotan(const Botan::ECDH_PublicKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+       ByteString inQ = BotanUtil::ecPoint2ByteString(inECKEY->public_point());
+       setQ(inQ);
+}
+
+// Check if the key is of the given type
+bool BotanECDHPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the ECDH public key components
+void BotanECDHPublicKey::setEC(const ByteString& inEC)
+{
+       ECPublicKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+void BotanECDHPublicKey::setQ(const ByteString& inQ)
+{
+       ECPublicKey::setQ(inQ);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Retrieve the Botan representation of the key
+Botan::ECDH_PublicKey* BotanECDHPublicKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+// Create the Botan representation of the key
+void BotanECDHPublicKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           q.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       Botan::PointGFp point = BotanUtil::byteString2ECPoint(q, group);
+                       eckey = new Botan::ECDH_PublicKey(group, point);
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h
new file mode 100644 (file)
index 0000000..0a10743
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDHPublicKey.h
+
+ Botan ECDH public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDHPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANECDHPUBLICKEY_H
+
+#include "config.h"
+#include "ECPublicKey.h"
+#include <botan/ecdh.h>
+
+class BotanECDHPublicKey : public ECPublicKey
+{
+public:
+       // Constructors
+       BotanECDHPublicKey();
+
+       BotanECDHPublicKey(const Botan::ECDH_PublicKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanECDHPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the ECDH public key components
+       virtual void setEC(const ByteString& inEC);
+       virtual void setQ(const ByteString& inQ);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::ECDH_PublicKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::ECDH_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::ECDH_PublicKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDHPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSA.cpp b/SoftHSMv2/src/lib/crypto/BotanECDSA.cpp
new file mode 100644 (file)
index 0000000..06b7a0f
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSA.cpp
+
+ Botan ECDSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDSA.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "ECParameters.h"
+#include "BotanECDSAKeyPair.h"
+#include "BotanUtil.h"
+#include <algorithm>
+#include <botan/ec_group.h>
+#include <botan/ecdsa.h>
+#include <botan/version.h>
+#include <iostream>
+
+// Constructor
+BotanECDSA::BotanECDSA()
+{
+       signer = NULL;
+       verifier = NULL;
+}
+
+// Destructor
+BotanECDSA::~BotanECDSA()
+{
+       delete signer;
+       delete verifier;
+}
+
+// Signing functions
+bool BotanECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                     ByteString& signature, const AsymMech::Type mechanism,
+                     const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       std::string emsa;
+
+       if (mechanism == AsymMech::ECDSA)
+       {
+               emsa = "Raw";
+       }
+        else
+        {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+               return false;
+        }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanECDSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+        BotanECDSAPrivateKey* pk = (BotanECDSAPrivateKey*) privateKey;
+        Botan::ECDSA_PrivateKey* botanKey = pk->getBotanKey();
+
+        if (botanKey == NULL)
+        {
+               ERROR_MSG("Could not get the Botan private key");
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+// Signing functions
+bool BotanECDSA::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                         const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+bool BotanECDSA::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+bool BotanECDSA::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+// Verification functions
+bool BotanECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                       const ByteString& signature, const AsymMech::Type mechanism,
+                       const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       std::string emsa;
+
+       if (mechanism == AsymMech::ECDSA)
+       {
+               emsa = "Raw";
+       }
+        else
+        {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanECDSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       BotanECDSAPublicKey* pk = (BotanECDSAPublicKey*) publicKey;
+       Botan::ECDSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (botanKey == NULL)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->verify_message(originalData.const_byte_str(),
+                                                       originalData.size(),
+                                                       signature.const_byte_str(),
+                                                       signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+// Verification functions
+bool BotanECDSA::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                           const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+bool BotanECDSA::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+bool BotanECDSA::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool BotanECDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                        ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDSA does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool BotanECDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                        ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDSA does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool BotanECDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for ECDSA key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+
+       // Generate the key-pair
+       Botan::ECDSA_PrivateKey* eckp = NULL;
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               eckp = new Botan::ECDSA_PrivateKey(*rng->getRNG(), BotanUtil::byteString2ECGroup(params->getEC()));
+       }
+       catch (...)
+       {
+               ERROR_MSG("ECDSA key generation failed");
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanECDSAKeyPair* kp = new BotanECDSAKeyPair();
+
+       ((BotanECDSAPublicKey*) kp->getPublicKey())->setFromBotan(eckp);
+       ((BotanECDSAPrivateKey*) kp->getPrivateKey())->setFromBotan(eckp);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete eckp;
+
+       return true;
+}
+
+unsigned long BotanECDSA::getMinKeySize()
+{
+       // Smallest EC group is secp112r1
+       return 112;
+}
+
+unsigned long BotanECDSA::getMaxKeySize()
+{
+       // Biggest EC group is secp521r1
+       return 521;
+}
+
+bool BotanECDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanECDSAKeyPair* kp = new BotanECDSAKeyPair();
+
+       bool rv = true;
+
+       if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanECDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanECDSAPublicKey* pub = new BotanECDSAPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanECDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanECDSAPrivateKey* priv = new BotanECDSAPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanECDSA::newPublicKey()
+{
+       return (PublicKey*) new BotanECDSAPublicKey();
+}
+
+PrivateKey* BotanECDSA::newPrivateKey()
+{
+       return (PrivateKey*) new BotanECDSAPrivateKey();
+}
+
+AsymmetricParameters* BotanECDSA::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool BotanECDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSA.h b/SoftHSMv2/src/lib/crypto/BotanECDSA.h
new file mode 100644 (file)
index 0000000..826d318
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSA.h
+
+ Botan ECDSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDSA_H
+#define _SOFTHSM_V2_BOTANECDSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanECDSA : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       BotanECDSA();
+
+       // Destructor
+       virtual ~BotanECDSA();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       Botan::PK_Signer* signer;
+       Botan::PK_Verifier* verifier;
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDSA_H
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp
new file mode 100644 (file)
index 0000000..ccc04d7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAKeyPair.cpp
+
+ Botan ECDSA key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDSAKeyPair.h"
+
+// Set the public key
+void BotanECDSAKeyPair::setPublicKey(BotanECDSAPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanECDSAKeyPair::setPrivateKey(BotanECDSAPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanECDSAKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanECDSAKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanECDSAKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanECDSAKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h
new file mode 100644 (file)
index 0000000..960923d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAKeyPair.h
+
+ Botan ECDSA key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDSAKEYPAIR_H
+#define _SOFTHSM_V2_BOTANECDSAKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanECDSAPublicKey.h"
+#include "BotanECDSAPrivateKey.h"
+
+class BotanECDSAKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanECDSAPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanECDSAPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanECDSAPublicKey pubKey;
+
+       // The private key
+       BotanECDSAPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDSAKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..a276cb0
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAPrivateKey.cpp
+
+ Botan ECDSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDSAPrivateKey.h"
+#include "BotanCryptoFactory.h"
+#include "BotanRNG.h"
+#include "BotanUtil.h"
+#include <string.h>
+#include <botan/pkcs8.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/asn1_oid.h>
+#include <botan/oids.h>
+#include <botan/version.h>
+
+// Constructors
+BotanECDSAPrivateKey::BotanECDSAPrivateKey()
+{
+       eckey = NULL;
+}
+
+BotanECDSAPrivateKey::BotanECDSAPrivateKey(const Botan::ECDSA_PrivateKey* inECKEY)
+{
+       eckey = NULL;
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanECDSAPrivateKey::~BotanECDSAPrivateKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanECDSAPrivateKey::type = "Botan ECDSA Private Key";
+
+// Get the base point order length
+unsigned long BotanECDSAPrivateKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Set from Botan representation
+void BotanECDSAPrivateKey::setFromBotan(const Botan::ECDSA_PrivateKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+       ByteString inD = BotanUtil::bigInt2ByteString(inECKEY->private_value());
+       setD(inD);
+}
+
+// Check if the key is of the given type
+bool BotanECDSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the ECDSA private key components
+void BotanECDSAPrivateKey::setD(const ByteString& inD)
+{
+       ECPrivateKey::setD(inD);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Setters for the ECDSA public key components
+void BotanECDSAPrivateKey::setEC(const ByteString& inEC)
+{
+       ECPrivateKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanECDSAPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       createBotanKey();
+       if (eckey == NULL) return der;
+       // Force EC_DOMPAR_ENC_OID
+       const size_t PKCS8_VERSION = 0;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+       const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->private_key_bits(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters);
+       const Botan::secure_vector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#else
+       const Botan::MemoryVector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID);
+       const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters);
+       const Botan::SecureVector<Botan::byte> ber =
+               Botan::DER_Encoder()
+               .start_cons(Botan::SEQUENCE)
+                   .encode(PKCS8_VERSION)
+                   .encode(alg_id)
+                   .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING)
+               .end_cons()
+           .get_contents();
+#endif
+       der.resize(ber.size());
+       memcpy(&der[0], &ber[0], ber.size());
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanECDSAPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
+       if (source.end_of_data()) return false;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> keydata;
+#else
+       Botan::SecureVector<Botan::byte> keydata;
+#endif
+       Botan::AlgorithmIdentifier alg_id;
+       Botan::ECDSA_PrivateKey* key = NULL;
+       try
+       {
+               Botan::BER_Decoder(source)
+               .start_cons(Botan::SEQUENCE)
+                       .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+                       .decode(alg_id)
+                       .decode(keydata, Botan::OCTET_STRING)
+                       .discard_remaining()
+               .end_cons();
+               if (keydata.empty())
+                       throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
+               if (Botan::OIDS::lookup(alg_id.oid).compare("ECDSA"))
+               {
+                       ERROR_MSG("Decoded private key not ECDSA");
+
+                       return false;
+               }
+               key = new Botan::ECDSA_PrivateKey(alg_id, keydata);
+               if (key == NULL) return false;
+
+               setFromBotan(key);
+
+               delete key;
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Decode failed on %s", e.what());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+Botan::ECDSA_PrivateKey* BotanECDSAPrivateKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+
+// Create the Botan representation of the key
+void BotanECDSAPrivateKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           d.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       eckey = new Botan::ECDSA_PrivateKey(*rng->getRNG(),
+                                                       group,
+                                                       BotanUtil::byteString2bigInt(d));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h
new file mode 100644 (file)
index 0000000..4477442
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAPrivateKey.h
+
+ Botan ECDSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDSAPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANECDSAPRIVATEKEY_H
+
+#include "config.h"
+#include "ECPrivateKey.h"
+#include <botan/ecdsa.h>
+
+class BotanECDSAPrivateKey : public ECPrivateKey
+{
+public:
+       // Constructors
+       BotanECDSAPrivateKey();
+
+       BotanECDSAPrivateKey(const Botan::ECDSA_PrivateKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanECDSAPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the ECDSA private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the ECDSA public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::ECDSA_PrivateKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::ECDSA_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::ECDSA_PrivateKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..3409d88
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAPublicKey.cpp
+
+ Botan ECDSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "BotanECDSAPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanECDSAPublicKey::BotanECDSAPublicKey()
+{
+       eckey = NULL;
+}
+
+BotanECDSAPublicKey::BotanECDSAPublicKey(const Botan::ECDSA_PublicKey* inECKEY)
+{
+       eckey = NULL;
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanECDSAPublicKey::~BotanECDSAPublicKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanECDSAPublicKey::type = "Botan ECDSA Public Key";
+
+// Get the base point order length
+unsigned long BotanECDSAPublicKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Set from Botan representation
+void BotanECDSAPublicKey::setFromBotan(const Botan::ECDSA_PublicKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+       ByteString inQ = BotanUtil::ecPoint2ByteString(inECKEY->public_point());
+       setQ(inQ);
+}
+
+// Check if the key is of the given type
+bool BotanECDSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the ECDSA public key components
+void BotanECDSAPublicKey::setEC(const ByteString& inEC)
+{
+       ECPublicKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+void BotanECDSAPublicKey::setQ(const ByteString& inQ)
+{
+       ECPublicKey::setQ(inQ);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Retrieve the Botan representation of the key
+Botan::ECDSA_PublicKey* BotanECDSAPublicKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+// Create the Botan representation of the key
+void BotanECDSAPublicKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           q.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       Botan::PointGFp point = BotanUtil::byteString2ECPoint(q, group);
+                       eckey = new Botan::ECDSA_PublicKey(group, point);
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h
new file mode 100644 (file)
index 0000000..6ad0720
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanECDSAPublicKey.h
+
+ Botan ECDSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANECDSAPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANECDSAPUBLICKEY_H
+
+#include "config.h"
+#include "ECPublicKey.h"
+#include <botan/ecdsa.h>
+
+class BotanECDSAPublicKey : public ECPublicKey
+{
+public:
+       // Constructors
+       BotanECDSAPublicKey();
+
+       BotanECDSAPublicKey(const Botan::ECDSA_PublicKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanECDSAPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the ECDSA public key components
+       virtual void setEC(const ByteString& inEC);
+       virtual void setQ(const ByteString& inQ);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::ECDSA_PublicKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::ECDSA_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::ECDSA_PublicKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANECDSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOST.cpp b/SoftHSMv2/src/lib/crypto/BotanGOST.cpp
new file mode 100644 (file)
index 0000000..ab02d54
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOST.cpp
+
+ Botan GOST R 34.10-2001 asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "BotanGOST.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "ECParameters.h"
+#include "BotanGOSTKeyPair.h"
+#include "BotanUtil.h"
+#include <algorithm>
+#include <botan/ec_group.h>
+#include <botan/gost_3410.h>
+#include <botan/version.h>
+#include <iostream>
+
+// Constructor
+BotanGOST::BotanGOST()
+{
+       signer = NULL;
+       verifier = NULL;
+}
+
+// Destructor
+BotanGOST::~BotanGOST()
+{
+       delete signer;
+       delete verifier;
+}
+
+// Signing functions
+bool BotanGOST::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                        const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanGOSTPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+
+       switch (mechanism)
+       {
+               case AsymMech::GOST:
+                       emsa = "Raw";
+                       break;
+               case AsymMech::GOST_GOST:
+                       emsa = "EMSA1(GOST-34.11)";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+       }
+
+        BotanGOSTPrivateKey* pk = (BotanGOSTPrivateKey*) currentPrivateKey;
+        Botan::GOST_3410_PrivateKey* botanKey = pk->getBotanKey();
+
+        if (botanKey == NULL)
+        {
+               ERROR_MSG("Could not get the Botan private key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanGOST::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (dataToSign.size() != 0)
+               {
+                       signer->update(dataToSign.const_byte_str(),
+                                      dataToSign.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanGOST::signFinal(ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->signature(*rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool BotanGOST::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                          const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanGOSTPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+
+       switch (mechanism)
+       {
+               case AsymMech::GOST:
+                       emsa = "Raw";
+                       break;
+               case AsymMech::GOST_GOST:
+                       emsa = "EMSA1(GOST-34.11)";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+       }
+
+       BotanGOSTPublicKey* pk = (BotanGOSTPublicKey*) currentPublicKey;
+       Botan::GOST_3410_PublicKey* botanKey = pk->getBotanKey();
+
+       if (botanKey == NULL)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanGOST::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (originalData.size() != 0)
+               {
+                       verifier->update(originalData.const_byte_str(),
+                                        originalData.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanGOST::verifyFinal(const ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->check_signature(signature.const_byte_str(), signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+// Encryption functions
+bool BotanGOST::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                       ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("GOST does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool BotanGOST::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                       ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("GOST does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool BotanGOST::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for GOST key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+
+       // Generate the key-pair
+       Botan::GOST_3410_PrivateKey* eckp = NULL;
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               eckp = new Botan::GOST_3410_PrivateKey(*rng->getRNG(), BotanUtil::byteString2ECGroup(params->getEC()));
+       }
+       catch (...)
+       {
+               ERROR_MSG("GOST key generation failed");
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanGOSTKeyPair* kp = new BotanGOSTKeyPair();
+
+       ((BotanGOSTPublicKey*) kp->getPublicKey())->setFromBotan(eckp);
+       ((BotanGOSTPrivateKey*) kp->getPrivateKey())->setFromBotan(eckp);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete eckp;
+
+       return true;
+}
+
+unsigned long BotanGOST::getMinKeySize()
+{
+       return 0;
+}
+
+unsigned long BotanGOST::getMaxKeySize()
+{
+       return 0;
+}
+
+bool BotanGOST::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanGOSTKeyPair* kp = new BotanGOSTKeyPair();
+
+       bool rv = true;
+
+       if (!((BotanGOSTPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((BotanGOSTPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanGOST::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanGOSTPublicKey* pub = new BotanGOSTPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanGOST::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanGOSTPrivateKey* priv = new BotanGOSTPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanGOST::newPublicKey()
+{
+       return (PublicKey*) new BotanGOSTPublicKey();
+}
+
+PrivateKey* BotanGOST::newPrivateKey()
+{
+       return (PrivateKey*) new BotanGOSTPrivateKey();
+}
+
+AsymmetricParameters* BotanGOST::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool BotanGOST::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOST.h b/SoftHSMv2/src/lib/crypto/BotanGOST.h
new file mode 100644 (file)
index 0000000..a8085ab
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOST.h
+
+ Botan GOST R 34.10-2001 asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANGOST_H
+#define _SOFTHSM_V2_BOTANGOST_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanGOST : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       BotanGOST();
+
+       // Destructor
+       virtual ~BotanGOST();
+
+       // Signing functions
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       Botan::PK_Signer* signer;
+       Botan::PK_Verifier* verifier;
+};
+
+#endif // !_SOFTHSM_V2_BOTANGOST_H
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp
new file mode 100644 (file)
index 0000000..08c3de5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTKeyPair.cpp
+
+ Botan GOST R 34.10-2001 key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "BotanGOSTKeyPair.h"
+
+// Set the public key
+void BotanGOSTKeyPair::setPublicKey(BotanGOSTPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanGOSTKeyPair::setPrivateKey(BotanGOSTPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanGOSTKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanGOSTKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanGOSTKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanGOSTKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h
new file mode 100644 (file)
index 0000000..2ff1b95
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTKeyPair.h
+
+ Botan GOST R 34.10-2001 key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANGOSTKEYPAIR_H
+#define _SOFTHSM_V2_BOTANGOSTKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanGOSTPublicKey.h"
+#include "BotanGOSTPrivateKey.h"
+
+class BotanGOSTKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanGOSTPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanGOSTPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanGOSTPublicKey pubKey;
+
+       // The private key
+       BotanGOSTPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANGOSTKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp
new file mode 100644 (file)
index 0000000..890f135
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTPrivateKey.cpp
+
+ Botan GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "BotanGOSTPrivateKey.h"
+#include "BotanCryptoFactory.h"
+#include "BotanRNG.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanGOSTPrivateKey::BotanGOSTPrivateKey()
+{
+       eckey = NULL;
+}
+
+BotanGOSTPrivateKey::BotanGOSTPrivateKey(const Botan::GOST_3410_PrivateKey* inECKEY)
+{
+       BotanGOSTPrivateKey();
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanGOSTPrivateKey::~BotanGOSTPrivateKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanGOSTPrivateKey::type = "Botan GOST Private Key";
+
+// Get the base point order length
+unsigned long BotanGOSTPrivateKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Get the output length
+unsigned long BotanGOSTPrivateKey::getOutputLength() const
+{
+       return getOrderLength() * 2;
+}
+
+// Set from Botan representation
+void BotanGOSTPrivateKey::setFromBotan(const Botan::GOST_3410_PrivateKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+       ByteString inD = BotanUtil::bigInt2ByteStringPrefix(inECKEY->private_value(), 32);
+       setD(inD);
+}
+
+// Check if the key is of the given type
+bool BotanGOSTPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the GOST private key components
+void BotanGOSTPrivateKey::setD(const ByteString& inD)
+{
+       GOSTPrivateKey::setD(inD);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+
+// Setters for the GOST public key components
+void BotanGOSTPrivateKey::setEC(const ByteString& inEC)
+{
+       GOSTPrivateKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Serialisation
+ByteString BotanGOSTPrivateKey::serialise() const
+{
+       return ec.serialise() +
+              d.serialise();
+}
+
+bool BotanGOSTPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dD = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dD.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setD(dD);
+
+       return true;
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanGOSTPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       // TODO
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanGOSTPrivateKey::PKCS8Decode(const ByteString& /*ber*/)
+{
+       return false;
+}
+
+// Retrieve the Botan representation of the key
+Botan::GOST_3410_PrivateKey* BotanGOSTPrivateKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+
+// Create the Botan representation of the key
+void BotanGOSTPrivateKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           d.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       eckey = new Botan::GOST_3410_PrivateKey(*rng->getRNG(),
+                                                       group,
+                                                       BotanUtil::byteString2bigInt(d));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h
new file mode 100644 (file)
index 0000000..cdc825b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTPrivateKey.h
+
+ Botan GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANGOSTPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANGOSTPRIVATEKEY_H
+
+#include "config.h"
+#include "GOSTPrivateKey.h"
+#include <botan/gost_3410.h>
+
+class BotanGOSTPrivateKey : public GOSTPrivateKey
+{
+public:
+       // Constructors
+       BotanGOSTPrivateKey();
+
+       BotanGOSTPrivateKey(const Botan::GOST_3410_PrivateKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanGOSTPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the GOST private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the GOST public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::GOST_3410_PrivateKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::GOST_3410_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::GOST_3410_PrivateKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANGOSTPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp
new file mode 100644 (file)
index 0000000..cebce66
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTPublicKey.cpp
+
+ Botan GOST R 34.10-2001 public key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "BotanGOSTPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanGOSTPublicKey::BotanGOSTPublicKey()
+{
+       eckey = NULL;
+}
+
+BotanGOSTPublicKey::BotanGOSTPublicKey(const Botan::GOST_3410_PublicKey* inECKEY)
+{
+       BotanGOSTPublicKey();
+
+       setFromBotan(inECKEY);
+}
+
+// Destructor
+BotanGOSTPublicKey::~BotanGOSTPublicKey()
+{
+       delete eckey;
+}
+
+// The type
+/*static*/ const char* BotanGOSTPublicKey::type = "Botan GOST Public Key";
+
+// Get the base point order length
+unsigned long BotanGOSTPublicKey::getOrderLength() const
+{
+       try
+       {
+               Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+               return group.get_order().bytes();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't get EC group for order length");
+
+               return 0;
+       }
+}
+
+// Get the output length
+unsigned long BotanGOSTPublicKey::getOutputLength() const
+{
+       return getOrderLength() * 2;
+}
+
+// Set from Botan representation
+void BotanGOSTPublicKey::setFromBotan(const Botan::GOST_3410_PublicKey* inECKEY)
+{
+       ByteString inEC = BotanUtil::ecGroup2ByteString(inECKEY->domain());
+       setEC(inEC);
+
+       ByteString inQ = BotanUtil::ecPoint2ByteString(inECKEY->public_point()).substr(3);
+
+       /* The points must be stored in little endian */
+       const size_t length = inQ.size() / 2;
+       for (size_t i = 0; i < (length / 2); i++)
+       {
+               std::swap(inQ[i], inQ[length-1-i]);
+               std::swap(inQ[length+i], inQ[2*length-1-i]);
+       }
+
+       setQ(inQ);
+}
+
+// Check if the key is of the given type
+bool BotanGOSTPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the GOST public key components
+void BotanGOSTPublicKey::setEC(const ByteString& inEC)
+{
+       GOSTPublicKey::setEC(inEC);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+void BotanGOSTPublicKey::setQ(const ByteString& inQ)
+{
+       GOSTPublicKey::setQ(inQ);
+
+       if (eckey)
+       {
+               delete eckey;
+               eckey = NULL;
+       }
+}
+
+// Serialisation
+ByteString BotanGOSTPublicKey::serialise() const
+{
+       return ec.serialise() +
+              q.serialise();
+}
+
+bool BotanGOSTPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dQ.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setQ(dQ);
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+Botan::GOST_3410_PublicKey* BotanGOSTPublicKey::getBotanKey()
+{
+       if (!eckey)
+       {
+               createBotanKey();
+       }
+
+       return eckey;
+}
+
+// Create the Botan representation of the key
+void BotanGOSTPublicKey::createBotanKey()
+{
+       if (ec.size() != 0 &&
+           q.size() != 0)
+       {
+               if (eckey)
+               {
+                       delete eckey;
+                       eckey = NULL;
+               }
+
+               try
+               {
+                       /* The points are stored in little endian */
+                       ByteString bPoint = q;
+                       const size_t length = bPoint.size() / 2;
+                       for (size_t i = 0; i < (length / 2); i++)
+                       {
+                               std::swap(bPoint[i], bPoint[length-1-i]);
+                               std::swap(bPoint[length+i], bPoint[2*length-1-i]);
+                       }
+                       ByteString p = "044104" + bPoint;
+
+                       Botan::EC_Group group = BotanUtil::byteString2ECGroup(ec);
+                       Botan::PointGFp point = BotanUtil::byteString2ECPoint(p, group);
+                       eckey = new Botan::GOST_3410_PublicKey(group, point);
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h
new file mode 100644 (file)
index 0000000..6d7e8fc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTPublicKey.h
+
+ Botan GOST R 34.11-2001 public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANGOSTPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANGOSTPUBLICKEY_H
+
+#include "config.h"
+#include "GOSTPublicKey.h"
+#include <botan/gost_3410.h>
+
+class BotanGOSTPublicKey : public GOSTPublicKey
+{
+public:
+       // Constructors
+       BotanGOSTPublicKey();
+
+       BotanGOSTPublicKey(const Botan::GOST_3410_PublicKey* inECKEY);
+
+       // Destructor
+       virtual ~BotanGOSTPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the GOST public key components
+       virtual void setEC(const ByteString& inEC);
+       virtual void setQ(const ByteString& inQ);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::GOST_3410_PublicKey* inECKEY);
+
+       // Retrieve the Botan representation of the key
+       Botan::GOST_3410_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::GOST_3410_PublicKey* eckey;
+
+       // Create the Botan representation of the key
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANGOSTPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp b/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp
new file mode 100644 (file)
index 0000000..344cdcd
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTR3411.cpp
+
+ Botan GOST R 34.11-94 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "BotanGOSTR3411.h"
+#include <botan/gost_3411.h>
+
+int BotanGOSTR3411::getHashSize()
+{
+       return 32;
+}
+
+Botan::HashFunction* BotanGOSTR3411::getHash() const
+{
+       return new Botan::GOST_34_11();
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h b/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h
new file mode 100644 (file)
index 0000000..b0ee374
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanGOSTR3411.h
+
+ Botan GOST R 34.11-94 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANGOSTR3411_H
+#define _SOFTHSM_V2_BOTANGOSTR3411_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanGOSTR3411 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANGOSTR3411_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp
new file mode 100644 (file)
index 0000000..9630dfc
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanHashAlgorithm.cpp
+
+ Base class for Botan hash algorithm classes
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/filters.h>
+
+// Base constructor 
+BotanHashAlgorithm::BotanHashAlgorithm()
+{
+       hash = NULL;
+}
+
+// Destructor
+BotanHashAlgorithm::~BotanHashAlgorithm()
+{
+       delete hash;
+}
+
+// Hashing functions
+bool BotanHashAlgorithm::hashInit()
+{
+       if (!HashAlgorithm::hashInit())
+       {
+               return false;
+       }
+
+       // Initialize digesting
+       try
+       {
+               if (hash == NULL)
+               {
+                       hash = getHash();
+               }
+               else
+               {
+                       hash->clear();
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to initialize the digesting token");
+
+               ByteString dummy;
+               HashAlgorithm::hashFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanHashAlgorithm::hashUpdate(const ByteString& data)
+{
+       if (!HashAlgorithm::hashUpdate(data))
+       {
+               return false;
+       }
+
+       // Continue digesting
+       try
+       {
+               if (data.size() != 0)
+               {
+                       hash->update(data.const_byte_str(), data.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to buffer data");
+
+               ByteString dummy;
+               HashAlgorithm::hashFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanHashAlgorithm::hashFinal(ByteString& hashedData)
+{
+       if (!HashAlgorithm::hashFinal(hashedData))
+       {
+               return false;
+       }
+
+       // Resize
+       hashedData.resize(hash->output_length());
+
+       // Read the digest
+       try
+       {
+               hash->final(&hashedData[0]);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to digest the data");
+
+               return false;
+       }
+
+       return true;
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h b/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h
new file mode 100644 (file)
index 0000000..dde82db
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanHashAlgorithm.h
+
+ Base class for Botan hash algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANHASHALGORITHM_H
+#define _SOFTHSM_V2_BOTANHASHALGORITHM_H
+
+#include "config.h"
+#include "HashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanHashAlgorithm : public HashAlgorithm
+{
+public:
+       // Base constructor
+       BotanHashAlgorithm();
+
+       // Destructor
+       virtual ~BotanHashAlgorithm();
+
+       // Hashing functions
+       virtual bool hashInit();
+       virtual bool hashUpdate(const ByteString& data);
+       virtual bool hashFinal(ByteString& hashedData);
+
+       virtual int getHashSize() = 0;
+protected:
+       virtual Botan::HashFunction* getHash() const = 0;
+
+private:
+       // Current hashing context
+       Botan::HashFunction *hash;
+};
+
+#endif // !_SOFTHSM_V2_BOTANHASHALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanMAC.cpp b/SoftHSMv2/src/lib/crypto/BotanMAC.cpp
new file mode 100644 (file)
index 0000000..b45f127
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanMAC.cpp
+
+ Botan MAC implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanMAC.h"
+
+std::string BotanHMACMD5::getAlgorithm() const
+{
+       return "HMAC(MD5)";
+}
+
+size_t BotanHMACMD5::getMacSize() const
+{
+       return 16;
+}
+
+std::string BotanHMACSHA1::getAlgorithm() const
+{
+       return "HMAC(SHA-1)";
+}
+
+size_t BotanHMACSHA1::getMacSize() const
+{
+       return 20;
+}
+
+std::string BotanHMACSHA224::getAlgorithm() const
+{
+       return "HMAC(SHA-224)";
+}
+
+size_t BotanHMACSHA224::getMacSize() const
+{
+       return 28;
+}
+
+std::string BotanHMACSHA256::getAlgorithm() const
+{
+       return "HMAC(SHA-256)";
+}
+
+size_t BotanHMACSHA256::getMacSize() const
+{
+       return 32;
+}
+
+std::string BotanHMACSHA384::getAlgorithm() const
+{
+       return "HMAC(SHA-384)";
+}
+
+size_t BotanHMACSHA384::getMacSize() const
+{
+       return 48;
+}
+
+std::string BotanHMACSHA512::getAlgorithm() const
+{
+       return "HMAC(SHA-512)";
+}
+
+size_t BotanHMACSHA512::getMacSize() const
+{
+       return 64;
+}
+
+#ifdef WITH_GOST
+std::string BotanHMACGOSTR3411::getAlgorithm() const
+{
+       return "HMAC(GOST-34.11)";
+}
+
+size_t BotanHMACGOSTR3411::getMacSize() const
+{
+       return 32;
+}
+#endif
+
+std::string BotanCMACDES::getAlgorithm() const
+{
+       switch(currentKey->getBitLen())
+       {
+               case 56:
+                       ERROR_MSG("Only supporting 3DES");
+                       return "";
+               case 112:
+               case 168:
+                       return "CMAC(TripleDES)";
+               default:
+                       break;
+       }
+
+       ERROR_MSG("Invalid DES bit len %i", currentKey->getBitLen());
+
+       return "";
+}
+
+size_t BotanCMACDES::getMacSize() const
+{
+       return 8;
+}
+
+std::string BotanCMACAES::getAlgorithm() const
+{
+       switch(currentKey->getBitLen())
+       {
+               case 128:
+                       return "CMAC(AES-128)";
+               case 192:
+                       return "CMAC(AES-192)";
+               case 256:
+                       return "CMAC(AES-256)";
+               default:
+                       break;
+       }
+
+       ERROR_MSG("Invalid AES bit len %i", currentKey->getBitLen());
+
+       return "";
+}
+
+size_t BotanCMACAES::getMacSize() const
+{
+       return 16;
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanMAC.h b/SoftHSMv2/src/lib/crypto/BotanMAC.h
new file mode 100644 (file)
index 0000000..4db9aee
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanMAC.h
+
+ Botan MAC implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANMAC_H
+#define _SOFTHSM_V2_BOTANMAC_H
+
+#include "config.h"
+#include "BotanMacAlgorithm.h"
+#include <botan/hmac.h>
+#include <botan/hash.h>
+
+class BotanHMACMD5 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanHMACSHA1 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanHMACSHA224 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanHMACSHA256 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanHMACSHA384 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanHMACSHA512 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+#ifdef WITH_GOST
+class BotanHMACGOSTR3411 : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+#endif
+
+class BotanCMACDES : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+class BotanCMACAES : public BotanMacAlgorithm
+{
+protected:
+       virtual std::string getAlgorithm() const;
+       virtual size_t getMacSize() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANMAC_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanMD5.cpp b/SoftHSMv2/src/lib/crypto/BotanMD5.cpp
new file mode 100644 (file)
index 0000000..382f53d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanMD5.cpp
+
+ Botan MD5 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanMD5.h"
+#include <botan/md5.h>
+
+int BotanMD5::getHashSize()
+{
+       return 16;
+}
+
+Botan::HashFunction* BotanMD5::getHash() const
+{
+       return new Botan::MD5();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanMD5.h b/SoftHSMv2/src/lib/crypto/BotanMD5.h
new file mode 100644 (file)
index 0000000..6542019
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanMD5.h
+
+ Botan MD5 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANMD5_H
+#define _SOFTHSM_V2_BOTANMD5_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanMD5 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANMD5_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp
new file mode 100644 (file)
index 0000000..6c863f7
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+// TODO: Store context in securely allocated memory
+
+/*****************************************************************************
+ BotanMacAlgorithm.cpp
+
+ Botan MAC algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanMacAlgorithm.h"
+#include "salloc.h"
+
+#include <botan/symkey.h>
+#include <botan/mac.h>
+#include <botan/botan.h>
+#include <botan/version.h>
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,26)
+#include <botan/lookup.h>
+#endif
+
+// Constructor
+BotanMacAlgorithm::BotanMacAlgorithm()
+{
+       mac = NULL;
+}
+
+// Destructor
+BotanMacAlgorithm::~BotanMacAlgorithm()
+{
+       delete mac;
+       mac = NULL;
+}
+
+// Signing functions
+bool BotanMacAlgorithm::signInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::signInit(key))
+       {
+               return false;
+       }
+
+       // Determine the hash name
+       std::string macName = getAlgorithm();
+
+       if (macName == "")
+       {
+               ERROR_MSG("Invalid sign mac algorithm");
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the context
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,26)
+               mac = Botan::MessageAuthenticationCode::create(macName).release();
+#else
+               mac = Botan::get_mac(macName);
+#endif
+               mac->set_key(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+       }
+       catch (std::exception &e)
+       {
+               ERROR_MSG("Failed to create the sign mac token: %s", e.what());
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanMacAlgorithm::signUpdate(const ByteString& dataToSign)
+{
+       if (!MacAlgorithm::signUpdate(dataToSign))
+       {
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       try
+       {
+               if (dataToSign.size() != 0)
+               {
+                       mac->update(dataToSign.const_byte_str(),
+                                    dataToSign.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to update the sign mac token");
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanMacAlgorithm::signFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               signResult = mac->final();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete mac;
+       mac = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool BotanMacAlgorithm::verifyInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::verifyInit(key))
+       {
+               return false;
+       }
+
+       // Determine the hash name
+       std::string macName = getAlgorithm();
+
+       if (macName == "")
+       {
+               ERROR_MSG("Invalid verify mac algorithm");
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the context
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,26)
+               mac = Botan::MessageAuthenticationCode::create(macName).release();
+#else
+               mac = Botan::get_mac(macName);
+#endif
+               mac->set_key(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+       }
+       catch (std::exception &e)
+       {
+               ERROR_MSG("Failed to create the verify mac token: %s", e.what());
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanMacAlgorithm::verifyUpdate(const ByteString& originalData)
+{
+       if (!MacAlgorithm::verifyUpdate(originalData))
+       {
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       try
+       {
+               if (originalData.size() != 0)
+               {
+                       mac->update(originalData.const_byte_str(),
+                                    originalData.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to update the verify mac token");
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanMacAlgorithm::verifyFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> macResult;
+#else
+       Botan::SecureVector<Botan::byte> macResult;
+#endif
+       try
+       {
+               macResult = mac->final();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to verify the data");
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       if (macResult.size() != signature.size())
+       {
+               ERROR_MSG("Bad verify result size");
+
+               delete mac;
+               mac = NULL;
+
+               return false;
+       }
+
+       delete mac;
+       mac = NULL;
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       return memcmp(&signature[0], macResult.data(), macResult.size()) == 0;
+#else
+       return memcmp(&signature[0], macResult.begin(), macResult.size()) == 0;
+#endif
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h b/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h
new file mode 100644 (file)
index 0000000..ac71009
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanMacAlgorithm.h
+
+ Botan MAC algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANMACALGORITHM_H
+#define _SOFTHSM_V2_BOTANMACALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "MacAlgorithm.h"
+#include <botan/mac.h>
+
+class BotanMacAlgorithm : public MacAlgorithm
+{
+public:
+       // Constructor
+       BotanMacAlgorithm();
+
+       // Destructor
+       virtual ~BotanMacAlgorithm();
+
+       // Signing functions
+       virtual bool signInit(const SymmetricKey* key);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(const SymmetricKey* key);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(ByteString& signature);
+
+       // Return the MAC size
+       virtual size_t getMacSize() const = 0;
+
+protected:
+       // Return the right algorithm for the operation
+       virtual std::string getAlgorithm() const = 0;
+
+private:
+       // The current context
+       Botan::MessageAuthenticationCode* mac;
+};
+
+#endif // !_SOFTHSM_V2_BOTANMACALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRNG.cpp b/SoftHSMv2/src/lib/crypto/BotanRNG.cpp
new file mode 100644 (file)
index 0000000..fa6509d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BOTANRNG.cpp
+
+ Botan random number generator class
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanRNG.h"
+
+#include <botan/version.h>
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+#include <botan/libstate.h>
+#else
+#include <botan/auto_rng.h>
+#endif
+
+// Base constructor
+BotanRNG::BotanRNG()
+{
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
+       rng = &Botan::global_state().global_rng();
+#else
+       rng = new Botan::AutoSeeded_RNG();
+#endif
+}
+
+// Destructor
+BotanRNG::~BotanRNG()
+{
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,14)
+       delete rng;
+#endif
+}
+
+// Generate random data
+bool BotanRNG::generateRandom(ByteString& data, const size_t len)
+{
+       data.wipe(len);
+
+       if (len > 0)
+               rng->randomize(&data[0], len);
+
+       return true;
+}
+
+// Seed the random pool
+void BotanRNG::seed(ByteString& seedData)
+{
+       rng->add_entropy(seedData.byte_str(), seedData.size());
+       // add_entropy will make sure the RNG is reseed so we do not need to call it.
+       // Made this change bacuase of API changes in Botan 1.11.31,
+       // but the statement above is also true for Botan 1.10.
+       // rng->reseed(seedData.size());
+}
+
+// Get the RNG
+Botan::RandomNumberGenerator* BotanRNG::getRNG()
+{
+       return rng;
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanRNG.h b/SoftHSMv2/src/lib/crypto/BotanRNG.h
new file mode 100644 (file)
index 0000000..f14b22e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRNG.h
+
+ Botan random number generator class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANRNG_H
+#define _SOFTHSM_V2_BOTANRNG_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "RNG.h"
+
+#include "botan/rng.h"
+
+class BotanRNG : public RNG
+{
+public:
+       // Base constructor
+       BotanRNG();
+
+       // Destructor
+       virtual ~BotanRNG();
+
+       // Generate random data
+       virtual bool generateRandom(ByteString& data, const size_t len);
+
+       // Seed the random pool
+       virtual void seed(ByteString& seedData);
+
+       // Get RNG
+       Botan::RandomNumberGenerator* getRNG();
+
+private:
+       // The RNG
+       Botan::RandomNumberGenerator* rng;
+};
+
+#endif // !_SOFTHSM_V2_BOTANRNG_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSA.cpp b/SoftHSMv2/src/lib/crypto/BotanRSA.cpp
new file mode 100644 (file)
index 0000000..2fbb4e2
--- /dev/null
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSA.cpp
+
+ Botan RSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanRSA.h"
+#include "BotanRNG.h"
+#include "CryptoFactory.h"
+#include "BotanCryptoFactory.h"
+#include "RSAParameters.h"
+#include "BotanRSAKeyPair.h"
+#include <algorithm>
+#include <botan/rsa.h>
+#include <botan/version.h>
+#include <sstream>
+
+// Constructor
+BotanRSA::BotanRSA()
+{
+       signer = NULL;
+       verifier = NULL;
+}
+
+// Destructor
+BotanRSA::~BotanRSA()
+{
+       delete signer;
+       delete verifier;
+}
+
+// Signing functions
+bool BotanRSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                   ByteString& signature, const AsymMech::Type mechanism,
+                   const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       std::string emsa = "";
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA:
+                       emsa = "Raw";
+                       break;
+               case AsymMech::RSA_PKCS:
+                       emsa = "EMSA3(Raw)";
+                       break;
+#ifdef WITH_RAW_PSS
+               case AsymMech::RSA_PKCS_PSS:
+                       emsa = getCipherRawPss(privateKey->getBitLength(), dataToSign.size(), param, paramLen);
+                       if (emsa == "")
+                       {
+                               return false;
+                       }
+                       break;
+#endif
+               default:
+                       // Call default implementation
+                       return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanRSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) privateKey;
+       Botan::RSA_PrivateKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan private key");
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Could not sign the data: %s", e.what());
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+bool BotanRSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                       const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanRSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+       std::ostringstream request;
+       size_t sLen;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       emsa = "EMSA3(MD5)";
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       emsa = "EMSA3(SHA-160)";
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       emsa = "EMSA3(SHA-224)";
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       emsa = "EMSA3(SHA-256)";
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       emsa = "EMSA3(SHA-384)";
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       emsa = "EMSA3(SHA-512)";
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-20))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-160,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-28))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-224,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-32))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-256,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-48))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-384,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-64))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-512,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SSL:
+                       emsa = "EMSA3(Parallel(MD5,SHA-160))";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+       }
+
+       BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) currentPrivateKey;
+       Botan::RSA_PrivateKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan private key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
+#else
+               signer = new Botan::PK_Signer(*botanKey, emsa);
+#endif
+               // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster.
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanRSA::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (dataToSign.size() != 0)
+               {
+                       signer->update(dataToSign.const_byte_str(),
+                                      dataToSign.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to signer token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanRSA::signFinal(ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the signature operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> signResult;
+#else
+       Botan::SecureVector<Botan::byte> signResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               signResult = signer->signature(*rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not sign the data");
+
+               delete signer;
+               signer = NULL;
+
+               return false;
+       }
+
+       // Return the result
+       signature.resize(signResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&signature[0], signResult.data(), signResult.size());
+#else
+       memcpy(&signature[0], signResult.begin(), signResult.size());
+#endif
+
+       delete signer;
+       signer = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool BotanRSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                     const ByteString& signature, const AsymMech::Type mechanism,
+                     const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       std::string emsa = "";
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA:
+                       emsa = "Raw";
+                       break;
+               case AsymMech::RSA_PKCS:
+                       emsa = "EMSA3(Raw)";
+                       break;
+#ifdef WITH_RAW_PSS
+               case AsymMech::RSA_PKCS_PSS:
+                       emsa = getCipherRawPss(publicKey->getBitLength(), originalData.size(), param, paramLen);
+                       if (emsa == "")
+                       {
+                               return false;
+                       }
+                       break;
+#endif
+               default:
+                       // Call the generic function
+                       return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanRSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       BotanRSAPublicKey* pk = (BotanRSAPublicKey*) publicKey;
+       Botan::RSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->verify_message(originalData.const_byte_str(),
+                                                       originalData.size(),
+                                                       signature.const_byte_str(),
+                                                       signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+bool BotanRSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                         const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanRSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       std::string emsa;
+       std::ostringstream request;
+       size_t sLen;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       emsa = "EMSA3(MD5)";
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       emsa = "EMSA3(SHA-160)";
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       emsa = "EMSA3(SHA-224)";
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       emsa = "EMSA3(SHA-256)";
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       emsa = "EMSA3(SHA-384)";
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       emsa = "EMSA3(SHA-512)";
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-20))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-160,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-28))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-224,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-32))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-256,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-48))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-384,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-64))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       request << "EMSA4(SHA-512,MGF1," << sLen << ")";
+                       emsa = request.str();
+                       break;
+               case AsymMech::RSA_SSL:
+                       emsa = "EMSA3(Parallel(MD5,SHA-160))";
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+       }
+
+       BotanRSAPublicKey* pk = (BotanRSAPublicKey*) currentPublicKey;
+       Botan::RSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       try
+       {
+               verifier = new Botan::PK_Verifier(*botanKey, emsa);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanRSA::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       try
+       {
+               if (originalData.size() != 0)
+               {
+                       verifier->update(originalData.const_byte_str(),
+                                        originalData.size());
+               }
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not add data to the verifier token");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanRSA::verifyFinal(const ByteString& signature)
+{
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+       bool verResult;
+       try
+       {
+               verResult = verifier->check_signature(signature.const_byte_str(), signature.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not check the signature");
+
+               delete verifier;
+               verifier = NULL;
+
+               return false;
+       }
+
+       delete verifier;
+       verifier = NULL;
+
+       return verResult;
+}
+
+// Encryption functions
+bool BotanRSA::encrypt(PublicKey* publicKey, const ByteString& data,
+                      ByteString& encryptedData, const AsymMech::Type padding)
+{
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(BotanRSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       std::string eme;
+
+       switch (padding)
+       {
+               case AsymMech::RSA_PKCS:
+                       eme = "PKCS1v15";
+                       break;
+               case AsymMech::RSA_PKCS_OAEP:
+                       eme = "EME1(SHA-160)";
+                       break;
+               case AsymMech::RSA:
+                       eme = "Raw";
+                       break;
+               default:
+                       ERROR_MSG("Invalid padding mechanism supplied (%i)", padding);
+
+                       return false;
+       }
+
+       BotanRSAPublicKey* pk = (BotanRSAPublicKey*) publicKey;
+       Botan::RSA_PublicKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan public key");
+
+               return false;
+       }
+
+       Botan::PK_Encryptor_EME* encryptor = NULL;
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               encryptor = new Botan::PK_Encryptor_EME(*botanKey, *rng->getRNG(), eme);
+#else
+               encryptor = new Botan::PK_Encryptor_EME(*botanKey, eme);
+#endif
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the encryptor token");
+
+               return false;
+       }
+
+       // Perform the encryption operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> encResult;
+#else
+       Botan::SecureVector<Botan::byte> encResult;
+#endif
+       try
+       {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               encResult = encryptor->encrypt(data.const_byte_str(), data.size(), *rng->getRNG());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not encrypt the data");
+
+               delete encryptor;
+
+               return false;
+       }
+
+       // Return the result
+       encryptedData.resize(encResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       memcpy(&encryptedData[0], encResult.data(), encResult.size());
+#else
+       memcpy(&encryptedData[0], encResult.begin(), encResult.size());
+#endif
+
+       delete encryptor;
+
+       return true;
+}
+
+// Decryption functions
+bool BotanRSA::decrypt(PrivateKey* privateKey, const ByteString& encryptedData,
+                      ByteString& data, const AsymMech::Type padding)
+{
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(BotanRSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       std::string eme;
+
+       switch (padding)
+       {
+               case AsymMech::RSA_PKCS:
+                       eme = "PKCS1v15";
+                       break;
+               case AsymMech::RSA_PKCS_OAEP:
+                       eme = "EME1(SHA-160)";
+                       break;
+               case AsymMech::RSA:
+                       eme = "Raw";
+                       break;
+               default:
+                       ERROR_MSG("Invalid padding mechanism supplied (%i)", padding);
+
+                       return false;
+       }
+
+       BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) privateKey;
+       Botan::RSA_PrivateKey* botanKey = pk->getBotanKey();
+
+       if (!botanKey)
+       {
+               ERROR_MSG("Could not get the Botan private key");
+
+               return false;
+       }
+
+       Botan::PK_Decryptor_EME* decryptor = NULL;
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               decryptor = new Botan::PK_Decryptor_EME(*botanKey, *rng->getRNG(), eme);
+#else
+               decryptor = new Botan::PK_Decryptor_EME(*botanKey, eme);
+#endif
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not create the decryptor token");
+
+               return false;
+       }
+
+       // Perform the decryption operation
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> decResult;
+#else
+       Botan::SecureVector<Botan::byte> decResult;
+#endif
+       try
+       {
+               decResult = decryptor->decrypt(encryptedData.const_byte_str(), encryptedData.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Could not decrypt the data");
+
+               delete decryptor;
+
+               return false;
+       }
+
+       // Return the result
+       if (padding == AsymMech::RSA)
+       {
+               // We compensate that Botan removes leading zeros
+               int modSize = pk->getN().size();
+               int decSize = decResult.size();
+               data.resize(modSize);
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&data[0] + modSize - decSize, decResult.data(), decSize);
+#else
+               memcpy(&data[0] + modSize - decSize, decResult.begin(), decSize);
+#endif
+       }
+       else
+       {
+               data.resize(decResult.size());
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               memcpy(&data[0], decResult.data(), decResult.size());
+#else
+               memcpy(&data[0], decResult.begin(), decResult.size());
+#endif
+       }
+
+       delete decryptor;
+
+       return true;
+}
+
+// Key factory
+bool BotanRSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(RSAParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for RSA key generation");
+
+               return false;
+       }
+
+       RSAParameters* params = (RSAParameters*) parameters;
+
+       if (params->getBitLength() < getMinKeySize() || params->getBitLength() > getMaxKeySize())
+       {
+               ERROR_MSG("This RSA key size (%lu) is not supported", params->getBitLength());
+
+               return false;
+       }
+
+       // Retrieve the desired public exponent
+       unsigned long e = params->getE().long_val();
+
+       // Check the public exponent
+       if ((e == 0) || (e % 2 != 1))
+       {
+               ERROR_MSG("Invalid RSA public exponent %d", e);
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       BotanRSAKeyPair* kp = new BotanRSAKeyPair();
+
+       // Generate the key-pair
+       Botan::RSA_PrivateKey* rsa = NULL;
+       try {
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               rsa = new Botan::RSA_PrivateKey(*rng->getRNG(), params->getBitLength(), e);
+       }
+       catch (std::exception& ex) {
+               ERROR_MSG("RSA key generation failed: %s", ex.what());
+
+               delete kp;
+
+               return false;
+       }
+
+       ((BotanRSAPublicKey*) kp->getPublicKey())->setFromBotan(rsa);
+       ((BotanRSAPrivateKey*) kp->getPrivateKey())->setFromBotan(rsa);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       delete rsa;
+
+       return true;
+}
+
+unsigned long BotanRSA::getMinKeySize()
+{
+       return 1024;
+}
+
+unsigned long BotanRSA::getMaxKeySize()
+{
+       return 4096;
+}
+
+bool BotanRSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       BotanRSAKeyPair* kp = new BotanRSAKeyPair();
+
+       bool rv = true;
+
+       if (!((RSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((RSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool BotanRSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanRSAPublicKey* pub = new BotanRSAPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool BotanRSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       BotanRSAPrivateKey* priv = new BotanRSAPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* BotanRSA::newPublicKey()
+{
+       return (PublicKey*) new BotanRSAPublicKey();
+}
+
+PrivateKey* BotanRSA::newPrivateKey()
+{
+       return (PrivateKey*) new BotanRSAPrivateKey();
+}
+
+AsymmetricParameters* BotanRSA::newParameters()
+{
+       return (AsymmetricParameters*) new RSAParameters();
+}
+
+bool BotanRSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       RSAParameters* params = new RSAParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+
+#ifdef WITH_RAW_PSS
+std::string BotanRSA::getCipherRawPss(size_t bitLength, size_t dataSize, const void* param, const size_t paramLen)
+{
+       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS))
+       {
+               ERROR_MSG("Invalid parameters");
+               return "";
+       }
+
+       std::string hashStr = "";
+       size_t allowedLen = 0;
+       switch (((RSA_PKCS_PSS_PARAMS*) param)->hashAlg)
+       {
+               case HashAlgo::SHA1:
+                       hashStr = "SHA-160";
+                       allowedLen = 20;
+                       break;
+               case HashAlgo::SHA224:
+                       hashStr = "SHA-224";
+                       allowedLen = 28;
+                       break;
+               case HashAlgo::SHA256:
+                       hashStr = "SHA-256";
+                       allowedLen = 32;
+                       break;
+               case HashAlgo::SHA384:
+                       hashStr = "SHA-384";
+                       allowedLen = 48;
+                       break;
+               case HashAlgo::SHA512:
+                       hashStr = "SHA-512";
+                       allowedLen = 64;
+                       break;
+               default:
+                       ERROR_MSG("Invalid hash parameter");
+                       return "";
+       }
+
+       if (dataSize != allowedLen)
+       {
+               ERROR_MSG("Data to sign does not match expected (%d) for RSA PSS", (int)allowedLen);
+               return "";
+       }
+
+       size_t sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+       if (sLen > ((bitLength+6)/8-2-20))
+       {
+               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                         (unsigned long)sLen, bitLength);
+               return "";
+       }
+
+       std::ostringstream request;
+       request << "PSSR_Raw(" << hashStr << ",MGF1," << sLen << ")";
+       return request.str();
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSA.h b/SoftHSMv2/src/lib/crypto/BotanRSA.h
new file mode 100644 (file)
index 0000000..f9b6554
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSA.h
+
+ Botan RSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANRSA_H
+#define _SOFTHSM_V2_BOTANRSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include <botan/pubkey.h>
+
+class BotanRSA : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       BotanRSA();
+
+       // Destructor
+       virtual ~BotanRSA();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       Botan::PK_Signer* signer;
+       Botan::PK_Verifier* verifier;
+
+#ifdef WITH_RAW_PSS
+       std::string getCipherRawPss(size_t bitLength, size_t dataSize, const void* param, const size_t paramLen);
+#endif
+};
+
+#endif // !_SOFTHSM_V2_BOTANRSA_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp b/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp
new file mode 100644 (file)
index 0000000..76d9b5b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAKeyPair.cpp
+
+ Botan RSA key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanRSAKeyPair.h"
+
+// Set the public key
+void BotanRSAKeyPair::setPublicKey(BotanRSAPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void BotanRSAKeyPair::setPrivateKey(BotanRSAPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* BotanRSAKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* BotanRSAKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* BotanRSAKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* BotanRSAKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h b/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h
new file mode 100644 (file)
index 0000000..55f4955
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAKeyPair.h
+
+ Botan RSA key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANRSAKEYPAIR_H
+#define _SOFTHSM_V2_BOTANRSAKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "BotanRSAPublicKey.h"
+#include "BotanRSAPrivateKey.h"
+
+class BotanRSAKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(BotanRSAPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(BotanRSAPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       BotanRSAPublicKey pubKey;
+
+       // The private key
+       BotanRSAPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_BOTANRSAKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..f600230
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAPrivateKey.cpp
+
+ Botan RSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanRSAPrivateKey.h"
+#include "BotanUtil.h"
+#include "BotanRNG.h"
+#include "BotanCryptoFactory.h"
+#include <string.h>
+#include <botan/pkcs8.h>
+#include <botan/pkcs8.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/oids.h>
+#include <botan/version.h>
+
+// Constructors
+BotanRSAPrivateKey::BotanRSAPrivateKey()
+{
+       rsa = NULL;
+}
+
+BotanRSAPrivateKey::BotanRSAPrivateKey(const Botan::RSA_PrivateKey* inRSA)
+{
+       rsa = NULL;
+
+       setFromBotan(inRSA);
+}
+
+// Destructor
+BotanRSAPrivateKey::~BotanRSAPrivateKey()
+{
+       delete rsa;
+}
+
+// The type
+/*static*/ const char* BotanRSAPrivateKey::type = "Botan RSA Private Key";
+
+// Set from Botan representation
+void BotanRSAPrivateKey::setFromBotan(const Botan::RSA_PrivateKey* inRSA)
+{
+       ByteString inP = BotanUtil::bigInt2ByteString(inRSA->get_p());
+       setP(inP);
+       ByteString inQ = BotanUtil::bigInt2ByteString(inRSA->get_q());
+       setQ(inQ);
+       ByteString inDP1 = BotanUtil::bigInt2ByteString(inRSA->get_d1());
+       setDP1(inDP1);
+       ByteString inDQ1 = BotanUtil::bigInt2ByteString(inRSA->get_d2());
+       setDQ1(inDQ1);
+       ByteString inPQ = BotanUtil::bigInt2ByteString(inRSA->get_c());
+       setPQ(inPQ);
+       ByteString inD = BotanUtil::bigInt2ByteString(inRSA->get_d());
+       setD(inD);
+       ByteString inN = BotanUtil::bigInt2ByteString(inRSA->get_n());
+       setN(inN);
+       ByteString inE = BotanUtil::bigInt2ByteString(inRSA->get_e());
+       setE(inE);
+}
+
+// Check if the key is of the given type
+bool BotanRSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the RSA private key components
+void BotanRSAPrivateKey::setP(const ByteString& inP)
+{
+       RSAPrivateKey::setP(inP);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setQ(const ByteString& inQ)
+{
+       RSAPrivateKey::setQ(inQ);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setPQ(const ByteString& inPQ)
+{
+       RSAPrivateKey::setPQ(inPQ);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setDP1(const ByteString& inDP1)
+{
+       RSAPrivateKey::setDP1(inDP1);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setDQ1(const ByteString& inDQ1)
+{
+       RSAPrivateKey::setDQ1(inDQ1);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setD(const ByteString& inD)
+{
+       RSAPrivateKey::setD(inD);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+
+// Setters for the RSA public key components
+void BotanRSAPrivateKey::setN(const ByteString& inN)
+{
+       RSAPrivateKey::setN(inN);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPrivateKey::setE(const ByteString& inE)
+{
+       RSAPrivateKey::setE(inE);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString BotanRSAPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       createBotanKey();
+       if (rsa == NULL) return der;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       const Botan::secure_vector<Botan::byte> ber = Botan::PKCS8::BER_encode(*rsa);
+#else
+       const Botan::SecureVector<Botan::byte> ber = Botan::PKCS8::BER_encode(*rsa);
+#endif
+       der.resize(ber.size());
+       memcpy(&der[0], &ber[0], ber.size());
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool BotanRSAPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
+       if (source.end_of_data()) return false;
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       Botan::secure_vector<Botan::byte> keydata;
+#else
+       Botan::SecureVector<Botan::byte> keydata;
+#endif
+       Botan::AlgorithmIdentifier alg_id;
+       Botan::RSA_PrivateKey* key = NULL;
+       try
+       {
+
+               Botan::BER_Decoder(source)
+               .start_cons(Botan::SEQUENCE)
+                       .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
+                       .decode(alg_id)
+                       .decode(keydata, Botan::OCTET_STRING)
+                       .discard_remaining()
+               .end_cons();
+               if (keydata.empty())
+                       throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
+               if (Botan::OIDS::lookup(alg_id.oid).compare("RSA"))
+               {
+                       ERROR_MSG("Decoded private key not RSA");
+
+                       return false;
+               }
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+               key = new Botan::RSA_PrivateKey(alg_id, keydata);
+#else
+               BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+               key = new Botan::RSA_PrivateKey(alg_id, keydata, *rng->getRNG());
+#endif
+               if (key == NULL) return false;
+
+               setFromBotan(key);
+
+               delete key;
+       }
+       catch (std::exception& e)
+       {
+               ERROR_MSG("Decode failed on %s", e.what());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve the Botan representation of the key
+Botan::RSA_PrivateKey* BotanRSAPrivateKey::getBotanKey()
+{
+       if (!rsa)
+       {
+               createBotanKey();
+       }
+
+       return rsa;
+}
+
+// Create the Botan representation of the key
+void BotanRSAPrivateKey::createBotanKey()
+{
+       // d and n is not needed, they can be calculated
+       if (p.size() != 0 &&
+           q.size() != 0 &&
+           e.size() != 0)
+       {
+               if (rsa)
+               {
+                       delete rsa;
+                       rsa = NULL;
+               }
+
+               try
+               {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+                       rsa = new Botan::RSA_PrivateKey(
+                                               BotanUtil::byteString2bigInt(p),
+                                               BotanUtil::byteString2bigInt(q),
+                                               BotanUtil::byteString2bigInt(e),
+                                               BotanUtil::byteString2bigInt(d),
+                                               BotanUtil::byteString2bigInt(n));
+#else
+                       BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
+                       rsa = new Botan::RSA_PrivateKey(*rng->getRNG(),
+                                               BotanUtil::byteString2bigInt(p),
+                                               BotanUtil::byteString2bigInt(q),
+                                               BotanUtil::byteString2bigInt(e),
+                                               BotanUtil::byteString2bigInt(d),
+                                               BotanUtil::byteString2bigInt(n));
+#endif
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan private key");
+               }
+        }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h
new file mode 100644 (file)
index 0000000..7664a86
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAPrivateKey.h
+
+ Botan RSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANRSAPRIVATEKEY_H
+#define _SOFTHSM_V2_BOTANRSAPRIVATEKEY_H
+
+#include "config.h"
+#include "RSAPrivateKey.h"
+#include <botan/rsa.h>
+
+class BotanRSAPrivateKey : public RSAPrivateKey
+{
+public:
+       // Constructors
+       BotanRSAPrivateKey();
+
+       BotanRSAPrivateKey(const Botan::RSA_PrivateKey* inRSA);
+
+       // Destructor
+       virtual ~BotanRSAPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the RSA private key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setPQ(const ByteString& inPQ);
+       virtual void setDP1(const ByteString& inDP1);
+       virtual void setDQ1(const ByteString& inDQ1);
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::RSA_PrivateKey* inRSA);
+
+       // Retrieve the Botan representation of the key
+       Botan::RSA_PrivateKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::RSA_PrivateKey* rsa;
+
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLRSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..63bc82c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAPublicKey.cpp
+
+ Botan RSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "BotanRSAPublicKey.h"
+#include "BotanUtil.h"
+#include <string.h>
+
+// Constructors
+BotanRSAPublicKey::BotanRSAPublicKey()
+{
+       rsa = NULL;
+}
+
+BotanRSAPublicKey::BotanRSAPublicKey(const Botan::RSA_PublicKey* inRSA)
+{
+       rsa = NULL;
+
+       setFromBotan(inRSA);
+}
+
+// Destructor
+BotanRSAPublicKey::~BotanRSAPublicKey()
+{
+       delete rsa;
+}
+
+// The type
+/*static*/ const char* BotanRSAPublicKey::type = "Botan RSA Public Key";
+
+// Check if the key is of the given type
+bool BotanRSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Set from OpenSSL representation
+void BotanRSAPublicKey::setFromBotan(const Botan::RSA_PublicKey* inRSA)
+{
+       ByteString inN = BotanUtil::bigInt2ByteString(inRSA->get_n());
+       setN(inN);
+       ByteString inE = BotanUtil::bigInt2ByteString(inRSA->get_e());
+       setE(inE);
+}
+
+// Setters for the RSA public key components
+void BotanRSAPublicKey::setN(const ByteString& inN)
+{
+       RSAPublicKey::setN(inN);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+void BotanRSAPublicKey::setE(const ByteString& inE)
+{
+       RSAPublicKey::setE(inE);
+
+       if (rsa)
+       {
+               delete rsa;
+               rsa = NULL;
+       }
+}
+
+// Retrieve the Botan representation of the key
+Botan::RSA_PublicKey* BotanRSAPublicKey::getBotanKey()
+{
+       if (!rsa)
+       {
+               createBotanKey();
+       }
+
+       return rsa;
+}
+
+// Create the Botan representation of the key
+void BotanRSAPublicKey::createBotanKey()
+{
+       if (n.size() != 0 && e.size() != 0)
+       {
+               if (rsa)
+               {
+                       delete rsa;
+                       rsa = NULL;
+               }
+
+               try
+               {
+                       rsa = new Botan::RSA_PublicKey(BotanUtil::byteString2bigInt(n),
+                                                       BotanUtil::byteString2bigInt(e));
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Could not create the Botan public key");
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h b/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h
new file mode 100644 (file)
index 0000000..a0c0026
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanRSAPublicKey.h
+
+ Botan RSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANRSAPUBLICKEY_H
+#define _SOFTHSM_V2_BOTANRSAPUBLICKEY_H
+
+#include "config.h"
+#include "RSAPublicKey.h"
+#include <botan/rsa.h>
+
+class BotanRSAPublicKey : public RSAPublicKey
+{
+public:
+       // Constructors
+       BotanRSAPublicKey();
+
+       BotanRSAPublicKey(const Botan::RSA_PublicKey* inRSA);
+
+       // Destructor
+       virtual ~BotanRSAPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Set from Botan representation
+       virtual void setFromBotan(const Botan::RSA_PublicKey* inRSA);
+
+       // Retrieve the Botan representation of the key
+       Botan::RSA_PublicKey* getBotanKey();
+
+private:
+       // The internal Botan representation
+       Botan::RSA_PublicKey* rsa;
+
+       void createBotanKey();
+};
+
+#endif // !_SOFTHSM_V2_BOTANRSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA1.cpp b/SoftHSMv2/src/lib/crypto/BotanSHA1.cpp
new file mode 100644 (file)
index 0000000..35846ec
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA1.cpp
+
+ Botan SHA1 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSHA1.h"
+#include <botan/sha160.h>
+
+int BotanSHA1::getHashSize()
+{
+       return 20;
+}
+
+Botan::HashFunction* BotanSHA1::getHash() const
+{
+       return new Botan::SHA_160();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA1.h b/SoftHSMv2/src/lib/crypto/BotanSHA1.h
new file mode 100644 (file)
index 0000000..ca336b0
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA1.h
+
+ Botan SHA1 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSHA1_H
+#define _SOFTHSM_V2_BOTANSHA1_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanSHA1 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSHA1_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA224.cpp b/SoftHSMv2/src/lib/crypto/BotanSHA224.cpp
new file mode 100644 (file)
index 0000000..f1d2268
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA224.cpp
+
+ Botan SHA224 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSHA224.h"
+#include <botan/sha2_32.h>
+
+int BotanSHA224::getHashSize()
+{
+       return 28;
+}
+
+Botan::HashFunction* BotanSHA224::getHash() const
+{
+       return new Botan::SHA_224();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA224.h b/SoftHSMv2/src/lib/crypto/BotanSHA224.h
new file mode 100644 (file)
index 0000000..61fe16c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA224.h
+
+ Botan SHA224 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSHA224_H
+#define _SOFTHSM_V2_BOTANSHA224_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanSHA224 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSHA224_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA256.cpp b/SoftHSMv2/src/lib/crypto/BotanSHA256.cpp
new file mode 100644 (file)
index 0000000..878dece
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA256.cpp
+
+ Botan SHA256 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSHA256.h"
+#include <botan/sha2_32.h>
+
+int BotanSHA256::getHashSize()
+{
+       return 32;
+}
+
+Botan::HashFunction* BotanSHA256::getHash() const
+{
+       return new Botan::SHA_256();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA256.h b/SoftHSMv2/src/lib/crypto/BotanSHA256.h
new file mode 100644 (file)
index 0000000..5561f3c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA256.h
+
+ Botan SHA256 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSHA256_H
+#define _SOFTHSM_V2_BOTANSHA256_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanSHA256 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSHA256_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA384.cpp b/SoftHSMv2/src/lib/crypto/BotanSHA384.cpp
new file mode 100644 (file)
index 0000000..b7a1e09
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA384.cpp
+
+ Botan SHA384 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSHA384.h"
+#include <botan/sha2_64.h>
+
+int BotanSHA384::getHashSize()
+{
+       return 48;
+}
+
+Botan::HashFunction* BotanSHA384::getHash() const
+{
+       return new Botan::SHA_384();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA384.h b/SoftHSMv2/src/lib/crypto/BotanSHA384.h
new file mode 100644 (file)
index 0000000..5cf5d98
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA384.h
+
+ Botan SHA384 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSHA384_H
+#define _SOFTHSM_V2_BOTANSHA384_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanSHA384 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSHA384_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA512.cpp b/SoftHSMv2/src/lib/crypto/BotanSHA512.cpp
new file mode 100644 (file)
index 0000000..b7aa459
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA512.cpp
+
+ Botan SHA512 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSHA512.h"
+#include <botan/sha2_64.h>
+
+int BotanSHA512::getHashSize()
+{
+       return 64;
+}
+
+Botan::HashFunction* BotanSHA512::getHash() const
+{
+       return new Botan::SHA_512();
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSHA512.h b/SoftHSMv2/src/lib/crypto/BotanSHA512.h
new file mode 100644 (file)
index 0000000..d72416e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSHA512.h
+
+ Botan SHA512 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSHA512_H
+#define _SOFTHSM_V2_BOTANSHA512_H
+
+#include "config.h"
+#include "BotanHashAlgorithm.h"
+#include <botan/hash.h>
+
+class BotanSHA512 : public BotanHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual Botan::HashFunction* getHash() const;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSHA512_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.cpp
new file mode 100644 (file)
index 0000000..3f13892
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+// TODO: Store context in securely allocated memory
+
+/*****************************************************************************
+ BotanSymmetricAlgorithm.cpp
+
+ Botan symmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanSymmetricAlgorithm.h"
+#include "BotanUtil.h"
+#include "salloc.h"
+#include <iostream>
+
+#include <botan/symkey.h>
+#include <botan/botan.h>
+#include <botan/version.h>
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,14)
+#include <botan/key_filt.h>
+#endif
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+#include "Botan_ecb.h"
+#include <botan/cipher_filter.h>
+#endif
+
+#ifdef WITH_AES_GCM
+#include <botan/aead.h>
+#endif
+
+// Constructor
+BotanSymmetricAlgorithm::BotanSymmetricAlgorithm()
+{
+       cryption = NULL;
+       maximumBytes = Botan::BigInt(1);
+       maximumBytes.flip_sign();
+       counterBytes = Botan::BigInt(0);
+}
+
+// Destructor
+BotanSymmetricAlgorithm::~BotanSymmetricAlgorithm()
+{
+       delete cryption;
+       cryption = NULL;
+}
+
+// Encryption functions
+bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode:CBC */, const ByteString& IV /* = ByteString()*/, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */)
+{
+       // Call the superclass initialiser
+       if (!SymmetricAlgorithm::encryptInit(key, mode, IV, padding, counterBits, aad, tagBytes))
+       {
+               return false;
+       }
+
+       // Check the IV
+       if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
+       {
+               ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       ByteString iv;
+
+       if (IV.size() > 0)
+       {
+               iv = IV;
+       }
+       else
+       {
+               iv.wipe(getBlockSize());
+       }
+
+       // Check the counter bits
+       if (counterBits > 0)
+       {
+               Botan::BigInt counter = BotanUtil::byteString2bigInt(iv);
+               counter.mask_bits(counterBits);
+
+               // Reverse the bits
+               while (counterBits > 0)
+               {
+                       counterBits--;
+                       if (counter.get_bit(counterBits))
+                       {
+                               counter.clear_bit(counterBits);
+                       }
+                       else
+                       {
+                               counter.set_bit(counterBits);
+                       }
+               }
+
+               // Set the maximum bytes
+               maximumBytes = (counter + 1) * getBlockSize();
+               counterBytes = Botan::BigInt(0);
+       }
+       else
+       {
+               maximumBytes = Botan::BigInt(1);
+               maximumBytes.flip_sign();
+       }
+
+       // Determine the cipher
+       std::string cipherName = getCipher();
+
+       if (cipherName == "")
+       {
+               ERROR_MSG("Invalid encryption cipher");
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the context
+       try
+       {
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+               if (mode == SymMode::ECB)
+               {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+                       // ECB cipher mode was dropped in Botan 2.0
+                       const std::vector<std::string> algo_parts = Botan::split_on(cipherName, '/');
+                       const std::string cipher_name = algo_parts[0];
+                       Botan::BlockCipherModePaddingMethod* pad;
+                       if (algo_parts.size() == 3 && algo_parts[2] == "PKCS7")
+                       {
+                               pad = new Botan::PKCS7_Padding();
+                       }
+                       else
+                       {
+                               pad = new Botan::Null_Padding();
+                       }
+                       std::unique_ptr<Botan::BlockCipher> bc(Botan::BlockCipher::create(cipher_name));
+                       Botan::Keyed_Filter* cipher = new Botan::Cipher_Mode_Filter(new Botan::ECB_Encryption(bc.release(),pad));
+                       cipher->set_key(botanKey);
+                       cryption = new Botan::Pipe(cipher);
+#else
+                       cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, Botan::ENCRYPTION));
+#endif
+               }
+#ifdef WITH_AES_GCM
+               else if (mode == SymMode::GCM)
+               {
+                       Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::ENCRYPTION);
+                       aead->set_key(botanKey);
+                       aead->set_associated_data(aad.const_byte_str(), aad.size());
+
+                       Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
+                       Botan::Keyed_Filter* filter = new Botan::Cipher_Mode_Filter(aead);
+                       filter->set_iv(botanIV);
+                       cryption = new Botan::Pipe(filter);
+               }
+#endif
+               else
+               {
+                       Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
+                       cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, botanIV, Botan::ENCRYPTION));
+               }
+               cryption->start_msg();
+       }
+       catch (std::exception &e)
+       {
+               ERROR_MSG("Failed to create the encryption token: %s", e.what());
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanSymmetricAlgorithm::encryptUpdate(const ByteString& data, ByteString& encryptedData)
+{
+       if (!SymmetricAlgorithm::encryptUpdate(data, encryptedData))
+       {
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Write data
+       try
+       {
+               if (data.size() > 0)
+                       cryption->write(data.const_byte_str(), data.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to write to the encryption token");
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Count number of bytes written
+       if (maximumBytes.is_positive())
+       {
+               counterBytes += data.size();
+       }
+
+       // Read data
+       int bytesRead = 0;
+       try
+       {
+               size_t outLen = cryption->remaining();
+               encryptedData.resize(outLen);
+               if (outLen > 0)
+                       bytesRead = cryption->read(&encryptedData[0], outLen);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to encrypt the data");
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Resize the output block
+       encryptedData.resize(bytesRead);
+       currentBufferSize -= bytesRead;
+
+       return true;
+}
+
+bool BotanSymmetricAlgorithm::encryptFinal(ByteString& encryptedData)
+{
+       if (!SymmetricAlgorithm::encryptFinal(encryptedData))
+       {
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Read data
+       int bytesRead = 0;
+       try
+       {
+               cryption->end_msg();
+               size_t outLen = cryption->remaining();
+               encryptedData.resize(outLen);
+               if (outLen > 0)
+                       bytesRead = cryption->read(&encryptedData[0], outLen);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to encrypt the data");
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Clean up
+       delete cryption;
+       cryption = NULL;
+
+       // Resize the output block
+       encryptedData.resize(bytesRead);
+
+       return true;
+}
+
+// Decryption functions
+bool BotanSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode::CBC */, const ByteString& IV /* = ByteString() */, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */)
+{
+       // Call the superclass initialiser
+       if (!SymmetricAlgorithm::decryptInit(key, mode, IV, padding, counterBits, aad, tagBytes))
+       {
+               return false;
+       }
+
+       // Check the IV
+       if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
+       {
+               ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       ByteString iv;
+
+       if (IV.size() > 0)
+       {
+               iv = IV;
+       }
+       else
+       {
+               iv.wipe(getBlockSize());
+       }
+
+       // Check the counter bits
+       if (counterBits > 0)
+       {
+               Botan::BigInt counter = BotanUtil::byteString2bigInt(iv);
+               counter.mask_bits(counterBits);
+
+               // Reverse the bits
+               while (counterBits > 0)
+               {
+                       counterBits--;
+                       if (counter.get_bit(counterBits))
+                       {
+                               counter.clear_bit(counterBits);
+                       }
+                       else
+                       {
+                               counter.set_bit(counterBits);
+                       }
+               }
+
+               // Set the maximum bytes
+               maximumBytes = (counter + 1) * getBlockSize();
+               counterBytes = Botan::BigInt(0);
+       }
+       else
+       {
+               maximumBytes = Botan::BigInt(1);
+               maximumBytes.flip_sign();
+       }
+
+       // Determine the cipher class
+       std::string cipherName = getCipher();
+
+       if (cipherName == "")
+       {
+               ERROR_MSG("Invalid decryption cipher");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the context
+       try
+       {
+               Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size());
+               if (mode == SymMode::ECB)
+               {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+                       // ECB cipher mode was dropped in Botan 2.0
+                       const std::vector<std::string> algo_parts = Botan::split_on(cipherName, '/');
+                       const std::string cipher_name = algo_parts[0];
+                       Botan::BlockCipherModePaddingMethod* pad;
+                       if (algo_parts.size() == 3 && algo_parts[2] == "PKCS7")
+                       {
+                               pad = new Botan::PKCS7_Padding();
+                       }
+                       else
+                       {
+                               pad = new Botan::Null_Padding();
+                       }
+                       std::unique_ptr<Botan::BlockCipher> bc(Botan::BlockCipher::create(cipher_name));
+                       Botan::Keyed_Filter* cipher = new Botan::Cipher_Mode_Filter(new Botan::ECB_Decryption(bc.release(),pad));
+                       cipher->set_key(botanKey);
+                       cryption = new Botan::Pipe(cipher);
+#else
+                       cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, Botan::DECRYPTION));
+#endif
+               }
+#ifdef WITH_AES_GCM
+               else if (mode == SymMode::GCM)
+               {
+                       Botan::AEAD_Mode* aead = Botan::get_aead(cipherName, Botan::DECRYPTION);
+                       aead->set_key(botanKey);
+                       aead->set_associated_data(aad.const_byte_str(), aad.size());
+
+                       Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
+                       Botan::Keyed_Filter* filter = new Botan::Cipher_Mode_Filter(aead);
+                       filter->set_iv(botanIV);
+                       cryption = new Botan::Pipe(filter);
+               }
+#endif
+               else
+               {
+                       Botan::InitializationVector botanIV = Botan::InitializationVector(IV.const_byte_str(), IV.size());
+                       cryption = new Botan::Pipe(Botan::get_cipher(cipherName, botanKey, botanIV, Botan::DECRYPTION));
+               }
+               cryption->start_msg();
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to create the decryption token");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool BotanSymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, ByteString& data)
+{
+       if (!SymmetricAlgorithm::decryptUpdate(encryptedData, data))
+       {
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // AEAD ciphers should not return decrypted data until final is called
+       if (currentCipherMode == SymMode::GCM)
+       {
+               data.resize(0);
+               return true;
+       }
+
+       // Write data
+       try
+       {
+               if (encryptedData.size() > 0)
+                       cryption->write(encryptedData.const_byte_str(), encryptedData.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to write to the decryption token");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Count number of bytes written
+       if (maximumBytes.is_positive())
+       {
+               counterBytes += encryptedData.size();
+       }
+
+       // Read data
+       int bytesRead = 0;
+       try
+       {
+               size_t outLen = cryption->remaining();
+               data.resize(outLen);
+               if (outLen > 0)
+                       bytesRead = cryption->read(&data[0], outLen);
+       }
+       catch (...)
+       {
+               ERROR_MSG("Failed to decrypt the data");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Resize the output block
+       data.resize(bytesRead);
+       currentBufferSize -= bytesRead;
+
+       return true;
+}
+
+bool BotanSymmetricAlgorithm::decryptFinal(ByteString& data)
+{
+       SymMode::Type mode = currentCipherMode;
+       ByteString aeadBuffer = currentAEADBuffer;
+
+       if (!SymmetricAlgorithm::decryptFinal(data))
+       {
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       if (mode == SymMode::GCM)
+       {
+               // Write data
+               try
+               {
+                       if (aeadBuffer.size() > 0)
+                               cryption->write(aeadBuffer.const_byte_str(), aeadBuffer.size());
+               }
+               catch (...)
+               {
+                       ERROR_MSG("Failed to write to the decryption token");
+
+                       delete cryption;
+                       cryption = NULL;
+
+                       return false;
+               }
+       }
+
+       // Read data
+       int bytesRead = 0;
+       try
+       {
+               cryption->end_msg();
+               size_t outLen = cryption->remaining();
+               data.resize(outLen);
+               if (outLen > 0)
+                       bytesRead = cryption->read(&data[0], outLen);
+       }
+       catch (std::exception &e)
+       {
+               ERROR_MSG("Failed to decrypt the data: %s", e.what());
+
+               delete cryption;
+               cryption = NULL;
+
+               return false;
+       }
+
+       // Clean up
+       delete cryption;
+       cryption = NULL;
+
+       // Resize the output block
+       data.resize(bytesRead);
+
+       return true;
+}
+
+// Check if more bytes of data can be encrypted
+bool BotanSymmetricAlgorithm::checkMaximumBytes(unsigned long bytes)
+{
+       if (maximumBytes.is_negative()) return true;
+
+       if (maximumBytes.cmp(counterBytes + bytes) >= 0) return true;
+
+       return false;
+}
diff --git a/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h b/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h
new file mode 100644 (file)
index 0000000..3031094
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanSymmetricAlgorithm.h
+
+ Botan symmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANSYMMETRICALGORITHM_H
+#define _SOFTHSM_V2_BOTANSYMMETRICALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "SymmetricAlgorithm.h"
+
+#include <botan/pipe.h>
+#include <botan/bigint.h>
+
+class BotanSymmetricAlgorithm : public SymmetricAlgorithm
+{
+public:
+       // Constructor
+       BotanSymmetricAlgorithm();
+
+       // Destructor
+       virtual ~BotanSymmetricAlgorithm();
+
+       // Encryption functions
+       virtual bool encryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool encryptUpdate(const ByteString& data, ByteString& encryptedData);
+       virtual bool encryptFinal(ByteString& encryptedData);
+
+       // Decryption functions
+       virtual bool decryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool decryptUpdate(const ByteString& encryptedData, ByteString& data);
+       virtual bool decryptFinal(ByteString& data);
+
+       // Return the block size
+       virtual size_t getBlockSize() const = 0;
+
+       // Check if more bytes of data can be encrypted
+       virtual bool checkMaximumBytes(unsigned long bytes);
+
+protected:
+       // Return the right cipher for the operation
+       virtual std::string getCipher() const = 0;
+
+private:
+       // The current context
+       Botan::Pipe* cryption;
+
+       // The maximum bytes to encrypt/decrypt
+       Botan::BigInt maximumBytes;
+       Botan::BigInt counterBytes;
+};
+
+#endif // !_SOFTHSM_V2_BOTANSYMMETRICALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/BotanUtil.cpp b/SoftHSMv2/src/lib/crypto/BotanUtil.cpp
new file mode 100644 (file)
index 0000000..e5da460
--- /dev/null
@@ -0,0 +1,146 @@
+ /*
+ * Copyright (c) .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanUtil.h
+
+ Botan convenience functions
+ *****************************************************************************/
+
+#include "config.h"
+#include "BotanUtil.h"
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/asn1_obj.h>
+#include <botan/version.h>
+
+// Convert a Botan BigInt to a ByteString
+ByteString BotanUtil::bigInt2ByteString(const Botan::BigInt& bigInt)
+{
+       ByteString rv;
+
+       rv.resize(bigInt.bytes());
+       bigInt.binary_encode(&rv[0]);
+
+       return rv;
+}
+
+// Used when extracting little-endian data
+ByteString BotanUtil::bigInt2ByteStringPrefix(const Botan::BigInt& bigInt, size_t size)
+{
+       ByteString rv;
+
+       if (size > bigInt.bytes())
+       {
+               size_t diff = size - bigInt.bytes();
+               rv.resize(size);
+
+               memset(&rv[0], '\0', diff);
+
+               bigInt.binary_encode(&rv[0] + diff);
+       }
+       else
+       {
+               rv.resize(bigInt.bytes());
+               bigInt.binary_encode(&rv[0]);
+       }
+
+       return rv;
+}
+
+// Convert a ByteString to an Botan BigInt
+Botan::BigInt BotanUtil::byteString2bigInt(const ByteString& byteString)
+{
+       return Botan::BigInt(byteString.const_byte_str(), byteString.size());
+}
+
+#if defined(WITH_ECC) || defined(WITH_GOST)
+// Convert a Botan EC group to a ByteString
+ByteString BotanUtil::ecGroup2ByteString(const Botan::EC_Group& ecGroup)
+{
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> der = ecGroup.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#else
+       Botan::SecureVector<Botan::byte> der = ecGroup.DER_encode(Botan::EC_DOMPAR_ENC_OID);
+#endif
+       return ByteString(&der[0], der.size());
+}
+
+// Convert a ByteString to a Botan EC group
+Botan::EC_Group BotanUtil::byteString2ECGroup(const ByteString& byteString)
+{
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> der(byteString.size());
+       memcpy(&der[0], byteString.const_byte_str(), byteString.size());
+       return Botan::EC_Group(der);
+#else
+       return Botan::EC_Group(Botan::MemoryVector<Botan::byte>(byteString.const_byte_str(), byteString.size()));
+#endif
+}
+
+// Convert a Botan EC point to a ByteString
+ByteString BotanUtil::ecPoint2ByteString(const Botan::PointGFp& ecPoint)
+{
+       ByteString point;
+
+       try
+       {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+               Botan::secure_vector<Botan::byte> repr = Botan::EC2OSP(ecPoint, Botan::PointGFp::UNCOMPRESSED);
+               Botan::secure_vector<Botan::byte> der;
+#else
+               Botan::SecureVector<Botan::byte> repr = Botan::EC2OSP(ecPoint, Botan::PointGFp::UNCOMPRESSED);
+               Botan::SecureVector<Botan::byte> der;
+#endif
+
+
+               der = Botan::DER_Encoder()
+                       .encode(repr, Botan::OCTET_STRING)
+                       .get_contents();
+               point.resize(der.size());
+               memcpy(&point[0], &der[0], der.size());
+       }
+       catch (...)
+       {
+               ERROR_MSG("Can't convert from EC point");
+       }
+       return point;
+}
+
+// Convert a ByteString to a Botan EC point
+Botan::PointGFp BotanUtil::byteString2ECPoint(const ByteString& byteString, const Botan::EC_Group& ecGroup)
+{
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
+       std::vector<Botan::byte> repr;
+#else
+       Botan::SecureVector<Botan::byte> repr;
+#endif
+       Botan::BER_Decoder(byteString.const_byte_str(), byteString.size())
+               .decode(repr, Botan::OCTET_STRING)
+               .verify_end();
+       return Botan::OS2ECP(&repr[0], repr.size(), ecGroup.get_curve());
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/BotanUtil.h b/SoftHSMv2/src/lib/crypto/BotanUtil.h
new file mode 100644 (file)
index 0000000..67f6ca6
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ BotanUtil.h
+
+ Botan convenience functions
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BOTANUTIL_H
+#define _SOFTHSM_V2_BOTANUTIL_H
+
+#include "config.h"
+#include "ByteString.h"
+#include <botan/bigint.h>
+#if defined(WITH_ECC) || defined(WITH_GOST)
+#include <botan/ec_group.h>
+#endif
+
+namespace BotanUtil
+{
+       // Convert a Botan BigInt to a ByteString
+       ByteString bigInt2ByteString(const Botan::BigInt& bigInt);
+       ByteString bigInt2ByteStringPrefix(const Botan::BigInt& bigInt, size_t size);
+
+       // Convert a ByteString to a Botan BigInt
+       Botan::BigInt byteString2bigInt(const ByteString& byteString);
+
+#if defined(WITH_ECC) || defined(WITH_GOST)
+       // Convert a Botan EC group to a ByteString
+       ByteString ecGroup2ByteString(const Botan::EC_Group& ecGroup);
+
+       // Convert a ByteString to a Botan EC group
+       Botan::EC_Group byteString2ECGroup(const ByteString& byteString);
+
+       // Convert a Botan EC point to a ByteString
+       ByteString ecPoint2ByteString(const Botan::PointGFp& ecPoint);
+
+       // Convert a ByteString to a Botan EC point in the given EC group
+       Botan::PointGFp byteString2ECPoint(const ByteString& byteString, const Botan::EC_Group& ecGroup);
+#endif
+}
+
+#endif // !_SOFTHSM_V2_BOTANUTIL_H
+
diff --git a/SoftHSMv2/src/lib/crypto/Botan_ecb.cpp b/SoftHSMv2/src/lib/crypto/Botan_ecb.cpp
new file mode 100644 (file)
index 0000000..f27276e
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+* ECB Mode
+* (C) 1999-2009,2013 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/version.h>
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+// ECB cipher mode was dropped in Botan 2.0.0
+// so including this code in SoftHSM for continued support
+// for e.g. CKA_VALUE_CHECK
+
+#include "Botan_ecb.h"
+#include "Botan_rounding.h"
+
+namespace Botan {
+
+ECB_Mode::ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
+   m_cipher(cipher),
+   m_padding(padding)
+   {
+   if(!m_padding->valid_blocksize(cipher->block_size()))
+      throw Invalid_Argument("Padding " + m_padding->name() +
+                                  " cannot be used with " +
+                                  cipher->name() + "/ECB");
+   }
+
+void ECB_Mode::clear()
+   {
+   m_cipher->clear();
+   }
+
+void ECB_Mode::reset()
+   {
+   // no msg state here
+   return;
+   }
+
+std::string ECB_Mode::name() const
+   {
+   return cipher().name() + "/ECB/" + padding().name();
+   }
+
+size_t ECB_Mode::update_granularity() const
+   {
+   return cipher().parallel_bytes();
+   }
+
+Key_Length_Specification ECB_Mode::key_spec() const
+   {
+   return cipher().key_spec();
+   }
+
+size_t ECB_Mode::default_nonce_length() const
+   {
+   return 0;
+   }
+
+bool ECB_Mode::valid_nonce_length(size_t n) const
+   {
+   return (n == 0);
+   }
+
+void ECB_Mode::key_schedule(const byte key[], size_t length)
+   {
+   m_cipher->set_key(key, length);
+   }
+
+void ECB_Mode::start_msg(const byte[], size_t nonce_len)
+   {
+   if(nonce_len != 0)
+      throw Invalid_IV_Length(name(), nonce_len);
+   }
+
+size_t ECB_Encryption::minimum_final_size() const
+   {
+   return 0;
+   }
+
+size_t ECB_Encryption::output_length(size_t input_length) const
+   {
+   if(input_length == 0)
+      return cipher().block_size();
+   else
+      return round_up(input_length, cipher().block_size());
+   }
+
+size_t ECB_Encryption::process(uint8_t buf[], size_t sz)
+   {
+   const size_t BS = cipher().block_size();
+   BOTAN_ASSERT(sz % BS == 0, "ECB input is full blocks");
+   const size_t blocks = sz / BS;
+   cipher().encrypt_n(buf, buf, blocks);
+   return sz;
+   }
+
+void ECB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
+   {
+   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
+   const size_t sz = buffer.size() - offset;
+
+   const size_t BS = cipher().block_size();
+
+   const size_t bytes_in_final_block = sz % BS;
+
+   padding().add_padding(buffer, bytes_in_final_block, BS);
+
+   if(buffer.size() % BS)
+      throw Exception("Did not pad to full block size in " + name());
+
+   update(buffer, offset);
+   }
+
+size_t ECB_Decryption::output_length(size_t input_length) const
+   {
+   return input_length;
+   }
+
+size_t ECB_Decryption::minimum_final_size() const
+   {
+   return cipher().block_size();
+   }
+
+size_t ECB_Decryption::process(uint8_t buf[], size_t sz)
+   {
+   const size_t BS = cipher().block_size();
+   BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
+   size_t blocks = sz / BS;
+   cipher().decrypt_n(buf, buf, blocks);
+   return sz;
+   }
+
+void ECB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
+   {
+   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
+   const size_t sz = buffer.size() - offset;
+
+   const size_t BS = cipher().block_size();
+
+   if(sz == 0 || sz % BS)
+      throw Decoding_Error(name() + ": Ciphertext not a multiple of block size");
+
+   update(buffer, offset);
+
+   const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS);
+   buffer.resize(buffer.size() - pad_bytes); // remove padding
+   }
+
+}
+
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/Botan_ecb.h b/SoftHSMv2/src/lib/crypto/Botan_ecb.h
new file mode 100644 (file)
index 0000000..1712083
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+* ECB Mode
+* (C) 1999-2009,2013 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_MODE_ECB_H__
+#define BOTAN_MODE_ECB_H__
+
+#include <botan/version.h>
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+// ECB cipher mode was dropped in Botan 2.0.0
+// so including this code in SoftHSM for continued support
+// for e.g. CKA_VALUE_CHECK
+
+#include <botan/cipher_mode.h>
+#include <botan/block_cipher.h>
+#include <botan/mode_pad.h>
+
+namespace Botan {
+
+/**
+* ECB mode
+*/
+class BOTAN_DLL ECB_Mode : public Cipher_Mode
+   {
+   public:
+      std::string name() const override;
+
+      size_t update_granularity() const override;
+
+      Key_Length_Specification key_spec() const override;
+
+      size_t default_nonce_length() const override;
+
+      bool valid_nonce_length(size_t n) const override;
+
+      void clear() override;
+
+      void reset() override;
+
+   protected:
+      ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding);
+
+      const BlockCipher& cipher() const { return *m_cipher; }
+
+      const BlockCipherModePaddingMethod& padding() const { return *m_padding; }
+
+   private:
+      void start_msg(const byte nonce[], size_t nonce_len) override;
+      void key_schedule(const byte key[], size_t length) override;
+
+      std::unique_ptr<BlockCipher> m_cipher;
+      std::unique_ptr<BlockCipherModePaddingMethod> m_padding;
+   };
+
+/**
+* ECB Encryption
+*/
+class BOTAN_DLL ECB_Encryption final : public ECB_Mode
+   {
+   public:
+      /**
+      * @param cipher block cipher to use
+      * @param padding padding method to use
+      */
+      ECB_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
+         ECB_Mode(cipher, padding) {}
+
+      size_t process(uint8_t buf[], size_t size) override;
+
+      void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
+
+      size_t output_length(size_t input_length) const override;
+
+      size_t minimum_final_size() const override;
+   };
+
+/**
+* ECB Decryption
+*/
+class BOTAN_DLL ECB_Decryption final : public ECB_Mode
+   {
+   public:
+      /**
+      * @param cipher block cipher to use
+      * @param padding padding method to use
+      */
+      ECB_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
+         ECB_Mode(cipher, padding) {}
+
+      size_t process(uint8_t buf[], size_t size) override;
+
+      void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
+
+      size_t output_length(size_t input_length) const override;
+
+      size_t minimum_final_size() const override;
+   };
+
+}
+
+#endif
+
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/Botan_rounding.h b/SoftHSMv2/src/lib/crypto/Botan_rounding.h
new file mode 100644 (file)
index 0000000..fbad3ae
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+* Integer Rounding Functions
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ROUNDING_H__
+#define BOTAN_ROUNDING_H__
+
+#include <botan/version.h>
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)
+// ECB cipher mode was dropped in Botan 2.0.0
+// so including this code in SoftHSM for continued support
+// for e.g. CKA_VALUE_CHECK
+
+#include <botan/types.h>
+#include <botan/assert.h>
+
+namespace Botan {
+
+/**
+* Round up
+* @param n a non-negative integer
+* @param align_to the alignment boundary
+* @return n rounded up to a multiple of align_to
+*/
+inline size_t round_up(size_t n, size_t align_to)
+   {
+   BOTAN_ASSERT(align_to != 0, "align_to must not be 0");
+
+   if(n % align_to)
+      n += align_to - (n % align_to);
+   return n;
+   }
+
+/**
+* Round down
+* @param n an integer
+* @param align_to the alignment boundary
+* @return n rounded down to a multiple of align_to
+*/
+template<typename T>
+inline T round_down(T n, T align_to)
+   {
+   if(align_to == 0)
+      return n;
+
+   return (n - (n % align_to));
+   }
+
+/**
+* Clamp
+*/
+inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound)
+   {
+   if(n < lower_bound)
+      return lower_bound;
+   if(n > upper_bound)
+      return upper_bound;
+   return n;
+   }
+
+}
+
+#endif
+
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/CryptoFactory.cpp b/SoftHSMv2/src/lib/crypto/CryptoFactory.cpp
new file mode 100644 (file)
index 0000000..c676676
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ CryptoFactory.cpp
+
+ This class is a factory for all cryptographic algorithm implementations. It
+ is an abstract base class for a factory that produces cryptographic library
+ specific implementations of cryptographic algorithms.
+ *****************************************************************************/
+
+#include "config.h"
+#include "CryptoFactory.h"
+
+#if defined(WITH_OPENSSL)
+
+#include "OSSLCryptoFactory.h"
+
+// Return the one-and-only instance
+CryptoFactory* CryptoFactory::i()
+{
+       return OSSLCryptoFactory::i();
+}
+
+// This will destroy the one-and-only instance.
+void CryptoFactory::reset()
+{
+       OSSLCryptoFactory::reset();
+}
+
+#elif defined(WITH_BOTAN)
+
+#include "BotanCryptoFactory.h"
+
+// Return the one-and-only instance
+CryptoFactory* CryptoFactory::i()
+{
+       return BotanCryptoFactory::i();
+}
+
+// This will destroy the one-and-only instance.
+void CryptoFactory::reset()
+{
+       BotanCryptoFactory::reset();
+}
+
+#else
+
+#error "You must configure a cryptographic library to use"
+
+#endif
+
+// Recycle a symmetric algorithm instance -- override this function in the derived
+// class if you need to perform specific clean-up
+void CryptoFactory::recycleSymmetricAlgorithm(SymmetricAlgorithm* toRecycle)
+{
+       delete toRecycle;
+}
+
+// Recycle an asymmetric algorithm instance -- override this function in the derived
+// class if you need to perform specific clean-up
+void CryptoFactory::recycleAsymmetricAlgorithm(AsymmetricAlgorithm* toRecycle)
+{
+       delete toRecycle;
+}
+
+// Recycle a hash algorithm instance -- override this function in the derived
+// class if you need to perform specific clean-up
+void CryptoFactory::recycleHashAlgorithm(HashAlgorithm* toRecycle)
+{
+       delete toRecycle;
+}
+
+// Recycle a MAC algorithm instance -- override this function in the derived
+// class if you need to perform specific clean-up
+void CryptoFactory::recycleMacAlgorithm(MacAlgorithm* toRecycle)
+{
+       delete toRecycle;
+}
diff --git a/SoftHSMv2/src/lib/crypto/CryptoFactory.h b/SoftHSMv2/src/lib/crypto/CryptoFactory.h
new file mode 100644 (file)
index 0000000..761e473
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ CryptoFactory.h
+
+ This class is a factory for all cryptographic algorithm implementations. It
+ is an abstract base class for a factory that produces cryptographic library
+ specific implementations of cryptographic algorithms.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_CRYPTOFACTORY_H
+#define _SOFTHSM_V2_CRYPTOFACTORY_H
+
+#include "config.h"
+#include "SymmetricAlgorithm.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "RNG.h"
+
+class CryptoFactory
+{
+public:
+       // Return the one-and-only instance
+       static CryptoFactory* i();
+
+       // This will destroy the one-and-only instance.
+       static void reset();
+
+#ifdef WITH_FIPS
+       // Return the FIPS 140-2 selftest status
+       virtual bool getFipsSelfTestStatus() const = 0;
+#endif
+
+       // Create a concrete instance of a symmetric algorithm
+       virtual SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type algorithm) = 0;
+
+       // Recycle a symmetric algorithm instance -- override this function in the derived
+       // class if you need to perform specific clean-up
+       virtual void recycleSymmetricAlgorithm(SymmetricAlgorithm* toRecycle);
+
+       // Create a concrete instance of an asymmetric algorithm
+       virtual AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type algorithm) = 0;
+
+       // Recycle an asymmetric algorithm instance -- override this function in the derived
+       // class if you need to perform specific clean-up
+       virtual void recycleAsymmetricAlgorithm(AsymmetricAlgorithm* toRecycle);
+
+       // Create a concrete instance of a hash algorithm
+       virtual HashAlgorithm* getHashAlgorithm(HashAlgo::Type algorithm) = 0;
+
+       // Recycle a hash algorithm instance -- override this function in the derived
+       // class if you need to perform specific clean-up
+       virtual void recycleHashAlgorithm(HashAlgorithm* toRecycle);
+
+       // Create a concrete instance of a MAC algorithm
+       virtual MacAlgorithm* getMacAlgorithm(MacAlgo::Type algorithm) = 0;
+
+       // Recycle a MAC algorithm instance -- override this function in the derived
+       // class if you need to perform specific clean-up
+       virtual void recycleMacAlgorithm(MacAlgorithm* toRecycle);
+
+       // Get the global RNG (may be an unique RNG per thread)
+       virtual RNG* getRNG(RNGImpl::Type name = RNGImpl::Default) = 0;
+
+       // Destructor
+       virtual ~CryptoFactory() { }
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_CRYPTOFACTORY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DESKey.cpp b/SoftHSMv2/src/lib/crypto/DESKey.cpp
new file mode 100644 (file)
index 0000000..1d5f9bc
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DESKey.cpp
+
+ DES key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+#include "DESKey.h"
+#include "CryptoFactory.h"
+
+// Set the key
+bool DESKey::setKeyBits(const ByteString& keybits)
+{
+       if (bitLen > 0)
+       {
+               // Check if the correct input data is supplied
+               size_t expectedLen = 0;
+
+               switch(bitLen)
+               {
+                       case 56:
+                               expectedLen = 8;
+                               break;
+                       case 112:
+                               expectedLen = 16;
+                               break;
+                       case 168:
+                               expectedLen = 24;
+                               break;
+               };
+
+               // Check the length
+               if (keybits.size() != expectedLen)
+               {
+                       return false;
+               }
+       }
+
+       keyData = keybits;
+
+       return true;
+}
+
+// Get key check value
+ByteString DESKey::getKeyCheckValue() const
+{
+       SymAlgo::Type algo = SymAlgo::Unknown;
+       ByteString iv;
+       ByteString data;
+       ByteString encryptedData;
+       ByteString encryptedFinal;
+
+
+       switch (this->getBitLen())
+       {
+               case 56:
+                       algo = SymAlgo::DES;
+                       break;
+               case 112:
+               case 168:
+                       algo = SymAlgo::DES3;
+                       break;
+               default:
+                       return encryptedData;
+       }
+
+       SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo);
+       if (cipher == NULL) return encryptedData;
+
+       // Single block of null (0x00) bytes
+       data.resize(cipher->getBlockSize());
+       memset(&data[0], 0, data.size());
+
+       if (!cipher->encryptInit(this, SymMode::ECB, iv, false) ||
+           !cipher->encryptUpdate(data, encryptedData) ||
+           !cipher->encryptFinal(encryptedFinal))
+       {
+               CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+               return encryptedData;
+       }
+       CryptoFactory::i()->recycleSymmetricAlgorithm(cipher);
+
+       encryptedData += encryptedFinal;
+       encryptedData.resize(3);
+
+       return encryptedData;
+}
diff --git a/SoftHSMv2/src/lib/crypto/DESKey.h b/SoftHSMv2/src/lib/crypto/DESKey.h
new file mode 100644 (file)
index 0000000..895e4fa
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DESKey.h
+
+ Base class for symmetric key classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DESKEY_H
+#define _SOFTHSM_V2_DESKEY_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+#include "SymmetricKey.h"
+
+class DESKey : public SymmetricKey
+{
+public:
+       // Base constructor
+       DESKey(size_t inBitLen = 0) : SymmetricKey(inBitLen) { }
+
+       // Set the key
+       virtual bool setKeyBits(const ByteString& keybits);
+
+       // Get the key check value
+       virtual ByteString getKeyCheckValue() const;
+};
+
+#endif // !_SOFTHSM_V2_DESKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DHParameters.cpp b/SoftHSMv2/src/lib/crypto/DHParameters.cpp
new file mode 100644 (file)
index 0000000..919901b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHParameters.cpp
+
+ Diffie-Hellman parameters (only used for key generation)
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DHParameters.h"
+#include <string.h>
+
+// The type
+/*static*/ const char* DHParameters::type = "Generic DH parameters";
+
+// Set the public prime p
+void DHParameters::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+// Set the generator g
+void DHParameters::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+// Set the optional bit length
+void DHParameters::setXBitLength(const size_t inBitLen)
+{
+       bitLen = inBitLen;
+}
+
+
+// Get the public prime p
+const ByteString& DHParameters::getP() const
+{
+       return p;
+}
+
+// Get the generator g
+const ByteString& DHParameters::getG() const
+{
+       return g;
+}
+
+// Get the optional bit length
+size_t DHParameters::getXBitLength() const
+{
+       return bitLen;
+}
+
+// Are the parameters of the given type?
+bool DHParameters::areOfType(const char* inType)
+{
+       return (strcmp(type, inType) == 0);
+}
+
+// Serialisation
+ByteString DHParameters::serialise() const
+{
+       ByteString len(bitLen);
+
+       return p.serialise() + g.serialise() + len.serialise();
+}
+
+bool DHParameters::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+       ByteString dLen = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dG.size() == 0) ||
+           (dLen.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setG(dG);
+       setXBitLength(dLen.long_val());
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DHParameters.h b/SoftHSMv2/src/lib/crypto/DHParameters.h
new file mode 100644 (file)
index 0000000..e0c963f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHParameters.h
+
+ Diffie-Hellman parameters (only used for key generation)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DHPARAMETERS_H
+#define _SOFTHSM_V2_DHPARAMETERS_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "AsymmetricParameters.h"
+
+class DHParameters : public AsymmetricParameters
+{
+public:
+       // Base constructors
+       DHParameters() : bitLen(0) { }
+
+       // The type
+       static const char* type;
+
+       // Set the public prime p
+       void setP(const ByteString& inP);
+
+       // Set the generator g
+       void setG(const ByteString& inG);
+
+       // Set the optional bit length
+       void setXBitLength(const size_t inBitLen);
+
+       // Get the public prime p
+       const ByteString& getP() const;
+
+       // Get the generator g
+       const ByteString& getG() const;
+
+       // Get the optional bit length
+       size_t getXBitLength() const;
+
+       // Are the parameters of the given type?
+       virtual bool areOfType(const char* inType);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+private:
+       ByteString p;
+       ByteString g;
+       size_t bitLen;
+};
+
+#endif // !_SOFTHSM_V2_DHPARAMETERS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp
new file mode 100644 (file)
index 0000000..41103f1
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHPrivateKey.cpp
+
+ Diffie-Hellman private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DHPrivateKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* DHPrivateKey::type = "Abstract DH private key";
+
+// Check if the key is of the given type
+bool DHPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long DHPrivateKey::getBitLength() const
+{
+       return getP().bits();
+}
+
+// Get the output length
+unsigned long DHPrivateKey::getOutputLength() const
+{
+       return getP().size();
+}
+
+// Setters for the DH private key components
+void DHPrivateKey::setX(const ByteString& inX)
+{
+       x = inX;
+}
+
+// Setters for the DH public key components
+void DHPrivateKey::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+void DHPrivateKey::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+// Getters for the DH private key components
+const ByteString& DHPrivateKey::getX() const
+{
+       return x;
+}
+
+// Getters for the DH public key components
+const ByteString& DHPrivateKey::getP() const
+{
+       return p;
+}
+
+const ByteString& DHPrivateKey::getG() const
+{
+       return g;
+}
+
+// Serialisation
+ByteString DHPrivateKey::serialise() const
+{
+       return p.serialise() +
+              g.serialise() +
+              x.serialise();
+}
+
+bool DHPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+       ByteString dX = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dG.size() == 0) ||
+           (dX.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setG(dG);
+       setX(dX);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DHPrivateKey.h b/SoftHSMv2/src/lib/crypto/DHPrivateKey.h
new file mode 100644 (file)
index 0000000..2c625da
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHPrivateKey.h
+
+ Diffie-Hellman private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DHPRIVATEKEY_H
+#define _SOFTHSM_V2_DHPRIVATEKEY_H
+
+#include "config.h"
+#include "PrivateKey.h"
+
+class DHPrivateKey : public PrivateKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the DH private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+
+       // Getters for the DH private key components
+       virtual const ByteString& getX() const;
+
+       // Getters for the DH public key components
+       virtual const ByteString& getP() const;
+       virtual const ByteString& getG() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Private components
+       ByteString x;
+
+       // Public components
+       ByteString p,g;
+};
+
+#endif // !_SOFTHSM_V2_DHPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DHPublicKey.cpp b/SoftHSMv2/src/lib/crypto/DHPublicKey.cpp
new file mode 100644 (file)
index 0000000..17e041d
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHPublicKey.cpp
+
+ Diffie-Hellman public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DHPublicKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* DHPublicKey::type = "Abstract DH public key";
+
+// Check if the key is of the given type
+bool DHPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long DHPublicKey::getBitLength() const
+{
+       return getP().bits();
+}
+
+// Get the output length
+unsigned long DHPublicKey::getOutputLength() const
+{
+       return getP().size();
+}
+
+// Setters for the DH public key components
+void DHPublicKey::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+void DHPublicKey::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+void DHPublicKey::setY(const ByteString& inY)
+{
+       y = inY;
+}
+
+// Getters for the DH public key components
+const ByteString& DHPublicKey::getP() const
+{
+       return p;
+}
+
+const ByteString& DHPublicKey::getG() const
+{
+       return g;
+}
+
+const ByteString& DHPublicKey::getY() const
+{
+       return y;
+}
+
+// Serialisation
+ByteString DHPublicKey::serialise() const
+{
+       return p.serialise() +
+              g.serialise() +
+              y.serialise();
+}
+
+bool DHPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+       ByteString dY = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dG.size() == 0) ||
+           (dY.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setG(dG);
+       setY(dY);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DHPublicKey.h b/SoftHSMv2/src/lib/crypto/DHPublicKey.h
new file mode 100644 (file)
index 0000000..a070eb8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHPublicKey.h
+
+ Diffie-Hellman public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DHPUBLICKEY_H
+#define _SOFTHSM_V2_DHPUBLICKEY_H
+
+#include "config.h"
+#include "PublicKey.h"
+
+class DHPublicKey : public PublicKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Getters for the DH public key components
+       virtual const ByteString& getP() const;
+       virtual const ByteString& getG() const;
+       virtual const ByteString& getY() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Public components
+       ByteString p,g,y;
+};
+
+#endif // !_SOFTHSM_V2_DHPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAParameters.cpp b/SoftHSMv2/src/lib/crypto/DSAParameters.cpp
new file mode 100644 (file)
index 0000000..79ef671
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAParameters.cpp
+
+ DSA parameters (only used for key generation)
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DSAParameters.h"
+#include <string.h>
+
+// The type
+/*static*/ const char* DSAParameters::type = "Generic DSA parameters";
+
+// Set the public prime p
+void DSAParameters::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+// Set the public subprime q
+void DSAParameters::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+// Set the generator g
+void DSAParameters::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+// Get the public prime p
+const ByteString& DSAParameters::getP() const
+{
+       return p;
+}
+
+// Get the public subprime q
+const ByteString& DSAParameters::getQ() const
+{
+       return q;
+}
+
+// Get the generator g
+const ByteString& DSAParameters::getG() const
+{
+       return g;
+}
+
+// Are the parameters of the given type?
+bool DSAParameters::areOfType(const char* inType)
+{
+       return (strcmp(type, inType) == 0);
+}
+
+// Serialisation
+ByteString DSAParameters::serialise() const
+{
+       return p.serialise() + q.serialise() + g.serialise();
+}
+
+bool DSAParameters::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dQ.size() == 0) ||
+           (dG.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setQ(dQ);
+       setG(dG);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAParameters.h b/SoftHSMv2/src/lib/crypto/DSAParameters.h
new file mode 100644 (file)
index 0000000..978bc09
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAParameters.h
+
+ DSA parameters (only used for key generation)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DSAPARAMETERS_H
+#define _SOFTHSM_V2_DSAPARAMETERS_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "AsymmetricParameters.h"
+
+class DSAParameters : public AsymmetricParameters
+{
+public:
+       // The type
+       static const char* type;
+
+       // Set the public prime p
+       void setP(const ByteString& inP);
+
+       // Set the public subprime q
+       void setQ(const ByteString& inQ);
+
+       // Set the generator g
+       void setG(const ByteString& inG);
+
+       // Get the public prime p
+       const ByteString& getP() const;
+
+       // Get the public subprime q
+       const ByteString& getQ() const;
+
+       // Get the generator g
+       const ByteString& getG() const;
+
+       // Are the parameters of the given type?
+       virtual bool areOfType(const char* inType);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+private:
+       ByteString p;
+       ByteString q;
+       ByteString g;
+};
+
+#endif // !_SOFTHSM_V2_DSAPARAMETERS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..1bdfd2d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAPrivateKey.cpp
+
+ DSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DSAPrivateKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* DSAPrivateKey::type = "Abstract DSA private key";
+
+// Check if the key is of the given type
+bool DSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long DSAPrivateKey::getBitLength() const
+{
+       return getP().bits();
+}
+
+// Get the output length
+unsigned long DSAPrivateKey::getOutputLength() const
+{
+       return getQ().size() * 2;
+}
+
+// Setters for the DSA private key components
+void DSAPrivateKey::setX(const ByteString& inX)
+{
+       x = inX;
+}
+
+// Setters for the DSA domain parameters
+void DSAPrivateKey::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+void DSAPrivateKey::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+void DSAPrivateKey::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+// Getters for the DSA private key components
+const ByteString& DSAPrivateKey::getX() const
+{
+       return x;
+}
+
+// Getters for the DSA domain parameters
+const ByteString& DSAPrivateKey::getP() const
+{
+       return p;
+}
+
+const ByteString& DSAPrivateKey::getQ() const
+{
+       return q;
+}
+
+const ByteString& DSAPrivateKey::getG() const
+{
+       return g;
+}
+
+// Serialisation
+ByteString DSAPrivateKey::serialise() const
+{
+       return p.serialise() +
+              q.serialise() +
+              g.serialise() +
+              x.serialise();
+}
+
+bool DSAPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+       ByteString dX = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dQ.size() == 0) ||
+           (dG.size() == 0) ||
+           (dX.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setQ(dQ);
+       setG(dG);
+       setX(dX);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/DSAPrivateKey.h
new file mode 100644 (file)
index 0000000..3b2070f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAPrivateKey.h
+
+ DSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DSAPRIVATEKEY_H
+#define _SOFTHSM_V2_DSAPRIVATEKEY_H
+
+#include "config.h"
+#include "PrivateKey.h"
+
+class DSAPrivateKey : public PrivateKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the DSA private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DSA domain parameters
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+
+       // Getters for the DSA private key components
+       virtual const ByteString& getX() const;
+
+       // Getters for the DSA domain parameters
+       virtual const ByteString& getP() const;
+       virtual const ByteString& getQ() const;
+       virtual const ByteString& getG() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Private components
+       ByteString x;
+
+       // Domain parameters
+       ByteString p,q,g;
+};
+
+#endif // !_SOFTHSM_V2_DSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..4439bdd
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAPublicKey.cpp
+
+ DSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "DSAPublicKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* DSAPublicKey::type = "Abstract DSA public key";
+
+// Check if the key is of the given type
+bool DSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long DSAPublicKey::getBitLength() const
+{
+       return getP().bits();
+}
+
+// Get the output length
+unsigned long DSAPublicKey::getOutputLength() const
+{
+       return getQ().size() * 2;
+}
+
+// Setters for the DSA public key components
+void DSAPublicKey::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+void DSAPublicKey::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+void DSAPublicKey::setG(const ByteString& inG)
+{
+       g = inG;
+}
+
+void DSAPublicKey::setY(const ByteString& inY)
+{
+       y = inY;
+}
+
+// Getters for the DSA public key components
+const ByteString& DSAPublicKey::getP() const
+{
+       return p;
+}
+
+const ByteString& DSAPublicKey::getQ() const
+{
+       return q;
+}
+
+const ByteString& DSAPublicKey::getG() const
+{
+       return g;
+}
+
+const ByteString& DSAPublicKey::getY() const
+{
+       return y;
+}
+
+// Serialisation
+ByteString DSAPublicKey::serialise() const
+{
+       return p.serialise() +
+              q.serialise() +
+              g.serialise() +
+              y.serialise();
+}
+
+bool DSAPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+       ByteString dG = ByteString::chainDeserialise(serialised);
+       ByteString dY = ByteString::chainDeserialise(serialised);
+
+       if ((dP.size() == 0) ||
+           (dQ.size() == 0) ||
+           (dG.size() == 0) ||
+           (dY.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setQ(dQ);
+       setG(dG);
+       setY(dY);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/DSAPublicKey.h b/SoftHSMv2/src/lib/crypto/DSAPublicKey.h
new file mode 100644 (file)
index 0000000..6d41e5d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSAPublicKey.h
+
+ DSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DSAPUBLICKEY_H
+#define _SOFTHSM_V2_DSAPUBLICKEY_H
+
+#include "config.h"
+#include "PublicKey.h"
+
+class DSAPublicKey : public PublicKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the DSA public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Getters for the DSA public key components
+       virtual const ByteString& getP() const;
+       virtual const ByteString& getQ() const;
+       virtual const ByteString& getG() const;
+       virtual const ByteString& getY() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Public components
+       ByteString p,q,g,y;
+};
+
+#endif // !_SOFTHSM_V2_DSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/ECParameters.cpp b/SoftHSMv2/src/lib/crypto/ECParameters.cpp
new file mode 100644 (file)
index 0000000..c4a6cfa
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECParameters.cpp
+
+ Elliptic Curve parameters (only used for key generation)
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "ECParameters.h"
+#include <string.h>
+
+// The type
+/*static*/ const char* ECParameters::type = "Generic EC parameters";
+
+// Set the curve OID ec
+void ECParameters::setEC(const ByteString& inEC)
+{
+       ec = inEC;
+}
+
+// Get the curve OID ec
+const ByteString& ECParameters::getEC() const
+{
+       return ec;
+}
+
+// Are the parameters of the given type?
+bool ECParameters::areOfType(const char* inType)
+{
+       return (strcmp(type, inType) == 0);
+}
+
+// Serialisation
+ByteString ECParameters::serialise() const
+{
+       return ec.serialise();
+}
+
+bool ECParameters::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+
+       if (dEC.size() == 0)
+       {
+               return false;
+       }
+
+       setEC(dEC);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/ECParameters.h b/SoftHSMv2/src/lib/crypto/ECParameters.h
new file mode 100644 (file)
index 0000000..76ca3e8
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECParameters.h
+
+ Elliptic Curve parameters (only used for key generation)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ECPARAMETERS_H
+#define _SOFTHSM_V2_ECPARAMETERS_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "AsymmetricParameters.h"
+
+class ECParameters : public AsymmetricParameters
+{
+public:
+       // The type
+       static const char* type;
+
+       // Set the curve OID ec
+       void setEC(const ByteString& inEC);
+
+       // Get the curve OID ec
+       const ByteString& getEC() const;
+
+       // Are the parameters of the given type?
+       virtual bool areOfType(const char* inType);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+private:
+       ByteString ec;
+};
+
+#endif // !_SOFTHSM_V2_ECPARAMETERS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp
new file mode 100644 (file)
index 0000000..f132f2e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECPrivateKey.cpp
+
+ Elliptic Curve private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "ECPrivateKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* ECPrivateKey::type = "Abstract EC private key";
+
+// Check if the key is of the given type
+bool ECPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long ECPrivateKey::getBitLength() const
+{
+       return getD().bits();
+}
+
+// Get the output length
+unsigned long ECPrivateKey::getOutputLength() const
+{
+       return getOrderLength() * 2;
+}
+
+// Setters for the EC private key components
+void ECPrivateKey::setD(const ByteString& inD)
+{
+       d = inD;
+}
+
+// Setters for the EC public key components
+void ECPrivateKey::setEC(const ByteString& inEC)
+{
+       ec = inEC;
+}
+
+// Getters for the EC private key components
+const ByteString& ECPrivateKey::getD() const
+{
+       return d;
+}
+
+// Getters for the EC public key components
+const ByteString& ECPrivateKey::getEC() const
+{
+       return ec;
+}
+
+// Serialisation
+ByteString ECPrivateKey::serialise() const
+{
+       return ec.serialise() +
+              d.serialise();
+}
+
+bool ECPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dD = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dD.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setD(dD);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/ECPrivateKey.h b/SoftHSMv2/src/lib/crypto/ECPrivateKey.h
new file mode 100644 (file)
index 0000000..0814181
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECPrivateKey.h
+
+ Elliptic Curve private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ECPRIVATEKEY_H
+#define _SOFTHSM_V2_ECPRIVATEKEY_H
+
+#include "config.h"
+#include "PrivateKey.h"
+
+class ECPrivateKey : public PrivateKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const = 0;
+
+       // Setters for the EC private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the EC public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Getters for the EC private key components
+       virtual const ByteString& getD() const;
+
+       // Getters for the EC public key components
+       virtual const ByteString& getEC() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Private components
+       ByteString d;
+
+       // Public components
+       ByteString ec;
+};
+
+#endif // !_SOFTHSM_V2_ECPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/ECPublicKey.cpp b/SoftHSMv2/src/lib/crypto/ECPublicKey.cpp
new file mode 100644 (file)
index 0000000..a92d137
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECPublicKey.cpp
+
+ Elliptic Curve public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "ECPublicKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* ECPublicKey::type = "Abstract EC public key";
+
+// Check if the key is of the given type
+bool ECPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long ECPublicKey::getBitLength() const
+{
+       return getQ().size() * 8;
+}
+
+// Get the output length
+unsigned long ECPublicKey::getOutputLength() const
+{
+       return getOrderLength() * 2;
+}
+
+// Setters for the EC public key components
+void ECPublicKey::setEC(const ByteString& inEC)
+{
+       ec = inEC;
+}
+
+void ECPublicKey::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+// Getters for the EC public key components
+const ByteString& ECPublicKey::getEC() const
+{
+       return ec;
+}
+
+const ByteString& ECPublicKey::getQ() const
+{
+       return q;
+}
+
+// Serialisation
+ByteString ECPublicKey::serialise() const
+{
+       return ec.serialise() +
+              q.serialise();
+}
+
+bool ECPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dQ.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setQ(dQ);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/ECPublicKey.h b/SoftHSMv2/src/lib/crypto/ECPublicKey.h
new file mode 100644 (file)
index 0000000..ce6cf63
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECPublicKey.h
+
+ Elliptic Curve public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ECPUBLICKEY_H
+#define _SOFTHSM_V2_ECPUBLICKEY_H
+
+#include "config.h"
+#include "PublicKey.h"
+
+class ECPublicKey : public PublicKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const = 0;
+
+       // Setters for the EC public key components
+       virtual void setEC(const ByteString& inEc);
+       virtual void setQ(const ByteString& inQ);
+
+       // Getters for the EC public key components
+       virtual const ByteString& getEC() const;
+       virtual const ByteString& getQ() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Public components
+       ByteString ec,q;
+};
+
+#endif // !_SOFTHSM_V2_ECPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp
new file mode 100644 (file)
index 0000000..9d23855
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ GOSTPrivateKey.cpp
+
+ GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "GOSTPrivateKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* GOSTPrivateKey::type = "Abstract GOST private key";
+
+// Check if the key is of the given type
+bool GOSTPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long GOSTPrivateKey::getBitLength() const
+{
+       return getD().bits();
+}
+
+// Setters for the GOST private key components
+void GOSTPrivateKey::setD(const ByteString& inD)
+{
+       d = inD;
+}
+
+// Setters for the GOST public key components
+void GOSTPrivateKey::setEC(const ByteString& inEC)
+{
+       ec = inEC;
+}
+
+// Getters for the GOST private key components
+const ByteString& GOSTPrivateKey::getD() const
+{
+       return d;
+}
+
+// Getters for the GOST public key components
+const ByteString& GOSTPrivateKey::getEC() const
+{
+       return ec;
+}
diff --git a/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h b/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h
new file mode 100644 (file)
index 0000000..929ddb1
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ GOSTPrivateKey.h
+
+ GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_GOSTPRIVATEKEY_H
+#define _SOFTHSM_V2_GOSTPRIVATEKEY_H
+
+#include "config.h"
+#include "PrivateKey.h"
+
+class GOSTPrivateKey : public PrivateKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const = 0;
+
+       // Setters for the GOST private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the GOST public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Getters for the GOST private key components
+       virtual const ByteString& getD() const;
+
+       // Getters for the GOST public key components
+       virtual const ByteString& getEC() const;
+
+       // Serialisation
+       virtual ByteString serialise() const = 0;
+       virtual bool deserialise(ByteString& serialised) = 0;
+
+protected:
+       // Private components
+       ByteString d;
+
+       // Public components
+       ByteString ec;
+};
+
+#endif // !_SOFTHSM_V2_GOSTPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp b/SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp
new file mode 100644 (file)
index 0000000..ad94068
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ GOSTPublicKey.cpp
+
+ GOST R 34.10-2001 public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "GOSTPublicKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* GOSTPublicKey::type = "Abstract GOST public key";
+
+// Check if the key is of the given type
+bool GOSTPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long GOSTPublicKey::getBitLength() const
+{
+       return getQ().size() * 8;
+}
+
+// Setters for the GOST public key components
+void GOSTPublicKey::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+// Setters for the GOST public key components
+void GOSTPublicKey::setEC(const ByteString& inEC)
+{
+       ec = inEC;
+}
+
+// Getters for the GOST public key components
+const ByteString& GOSTPublicKey::getQ() const
+{
+       return q;
+}
+
+// Getters for the GOST public key components
+const ByteString& GOSTPublicKey::getEC() const
+{
+       return ec;
+}
diff --git a/SoftHSMv2/src/lib/crypto/GOSTPublicKey.h b/SoftHSMv2/src/lib/crypto/GOSTPublicKey.h
new file mode 100644 (file)
index 0000000..28de7b8
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ GOSTPublicKey.h
+
+ GOST R 34.10-2001 public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_GOSTPUBLICKEY_H
+#define _SOFTHSM_V2_GOSTPUBLICKEY_H
+
+#include "config.h"
+#include "PublicKey.h"
+
+class GOSTPublicKey : public PublicKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const = 0;
+
+       // Setters for the GOST public key components
+       virtual void setQ(const ByteString& inQ);
+       virtual void setEC(const ByteString& inEC);
+
+       // Getters for the GOST public key components
+       virtual const ByteString& getQ() const;
+       virtual const ByteString& getEC() const;
+
+       // Serialisation
+       virtual ByteString serialise() const = 0;
+       virtual bool deserialise(ByteString& serialised) = 0;
+
+protected:
+       // Public components
+       ByteString q, ec;
+};
+
+#endif // !_SOFTHSM_V2_GOSTPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp
new file mode 100644 (file)
index 0000000..934a64c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ HashAlgorithm.cpp
+
+ Base class for hash algorithm classes
+ *****************************************************************************/
+
+#include "config.h"
+#include "HashAlgorithm.h"
+
+// Base constructor
+HashAlgorithm::HashAlgorithm()
+{
+       currentOperation = NONE;
+}
+
+// Hashing functions
+bool HashAlgorithm::hashInit()
+{
+       if (currentOperation != NONE)
+       {
+               return false;
+       }
+
+       currentOperation = HASHING;
+
+       return true;
+}
+
+bool HashAlgorithm::hashUpdate(const ByteString& /*data*/)
+{
+       if (currentOperation != HASHING)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool HashAlgorithm::hashFinal(ByteString& /*hashedData*/)
+{
+       if (currentOperation != HASHING)
+       {
+               return false;
+       }
+
+       currentOperation = NONE;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/HashAlgorithm.h b/SoftHSMv2/src/lib/crypto/HashAlgorithm.h
new file mode 100644 (file)
index 0000000..ca2ae08
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ HashAlgorithm.h
+
+ Base class for hash algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HASHALGORITHM_H
+#define _SOFTHSM_V2_HASHALGORITHM_H
+
+#include "config.h"
+#include "ByteString.h"
+
+struct HashAlgo
+{
+       enum Type
+       {
+               Unknown,
+               MD5,
+               SHA1,
+               SHA224,
+               SHA256,
+               SHA384,
+               SHA512,
+               GOST
+       };
+};
+
+class HashAlgorithm
+{
+public:
+       // Base constructors
+       HashAlgorithm();
+
+       // Destructor
+       virtual ~HashAlgorithm() { }
+
+       // Hashing functions
+       virtual bool hashInit();
+       virtual bool hashUpdate(const ByteString& data);
+       virtual bool hashFinal(ByteString& hashedData);
+
+       virtual int getHashSize() = 0;
+protected:
+       // The current operation
+       enum
+       {
+               NONE,
+               HASHING
+       }
+       currentOperation;
+};
+
+#endif // !_SOFTHSM_V2_HASHALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp
new file mode 100644 (file)
index 0000000..e100dc1
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MacAlgorithm.cpp
+
+ Base class for MAC algorithm classes
+ *****************************************************************************/
+
+#include "MacAlgorithm.h"
+#include <algorithm>
+#include <string.h>
+
+MacAlgorithm::MacAlgorithm()
+{
+       currentOperation = NONE;
+       currentKey = NULL;
+}
+
+bool MacAlgorithm::signInit(const SymmetricKey* key)
+{
+       if ((key == NULL) || (currentOperation != NONE))
+       {
+               return false;
+       }
+
+       currentKey = key;
+       currentOperation = SIGN;
+
+       return true;
+}
+
+bool MacAlgorithm::signUpdate(const ByteString& /*dataToSign*/)
+{
+       if (currentOperation != SIGN)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool MacAlgorithm::signFinal(ByteString& /*signature*/)
+{
+       if (currentOperation != SIGN)
+       {
+               return false;
+       }
+
+       currentOperation = NONE;
+       currentKey = NULL;
+
+       return true;
+}
+
+bool MacAlgorithm::verifyInit(const SymmetricKey* key)
+{
+       if ((key == NULL) || (currentOperation != NONE))
+       {
+               return false;
+       }
+
+       currentOperation = VERIFY;
+       currentKey = key;
+
+       return true;
+}
+
+bool MacAlgorithm::verifyUpdate(const ByteString& /*originalData*/)
+{
+       if (currentOperation != VERIFY)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool MacAlgorithm::verifyFinal(ByteString& /*signature*/)
+{
+       if (currentOperation != VERIFY)
+       {
+               return false;
+       }
+
+       currentOperation = NONE;
+       currentKey = NULL;
+
+       return true;
+}
+
+unsigned long MacAlgorithm::getMinKeySize()
+{
+       return 0;
+}
+
+unsigned long MacAlgorithm::getMaxKeySize()
+{
+       return 0;
+}
+
+void MacAlgorithm::recycleKey(SymmetricKey* toRecycle)
+{
+       delete toRecycle;
+}
diff --git a/SoftHSMv2/src/lib/crypto/MacAlgorithm.h b/SoftHSMv2/src/lib/crypto/MacAlgorithm.h
new file mode 100644 (file)
index 0000000..e9b22b0
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MacAlgorithm.h
+
+ Base class for MAC algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_MACALGORITHM_H
+#define _SOFTHSM_V2_MACALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "RNG.h"
+
+struct MacAlgo
+{
+       enum Type
+       {
+               Unknown,
+               HMAC_MD5,
+               HMAC_SHA1,
+               HMAC_SHA224,
+               HMAC_SHA256,
+               HMAC_SHA384,
+               HMAC_SHA512,
+               HMAC_GOST,
+               CMAC_DES,
+               CMAC_AES
+       };
+};
+
+class MacAlgorithm
+{
+public:
+       // Base constructors
+       MacAlgorithm();
+
+       // Destructor
+       virtual ~MacAlgorithm() { }
+
+       // Signing functions
+       virtual bool signInit(const SymmetricKey* key);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(const SymmetricKey* key);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(ByteString& signature);
+
+       // Key
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual void recycleKey(SymmetricKey* toRecycle);
+
+       // Return the MAC size
+       virtual size_t getMacSize() const = 0;
+
+protected:
+       // The current key
+       const SymmetricKey* currentKey;
+
+private:
+       // The current operation
+       enum
+       {
+               NONE,
+               SIGN,
+               VERIFY
+       } 
+       currentOperation;
+};
+
+#endif // !_SOFTHSM_V2_MACALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/Makefile.am b/SoftHSMv2/src/lib/crypto/Makefile.am
new file mode 100644 (file)
index 0000000..f65e0a4
--- /dev/null
@@ -0,0 +1,126 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../common \
+                               -I$(srcdir)/../data_mgr \
+                               -I$(srcdir)/../pkcs11 \
+                               @CRYPTO_INCLUDES@
+
+noinst_LTLIBRARIES =           libsofthsm_crypto.la
+libsofthsm_crypto_la_SOURCES = AESKey.cpp \
+                               AsymmetricAlgorithm.cpp \
+                               AsymmetricKeyPair.cpp \
+                               CryptoFactory.cpp \
+                               DESKey.cpp \
+                               DHParameters.cpp \
+                               DHPublicKey.cpp \
+                               DHPrivateKey.cpp \
+                               DSAParameters.cpp \
+                               DSAPublicKey.cpp \
+                               DSAPrivateKey.cpp \
+                               ECParameters.cpp \
+                               ECPublicKey.cpp \
+                               ECPrivateKey.cpp \
+                               GOSTPublicKey.cpp \
+                               GOSTPrivateKey.cpp \
+                               HashAlgorithm.cpp \
+                               MacAlgorithm.cpp \
+                               RSAParameters.cpp \
+                               RSAPrivateKey.cpp \
+                               RSAPublicKey.cpp \
+                               SymmetricAlgorithm.cpp \
+                               SymmetricKey.cpp
+libsofthsm_crypto_la_LIBADD =  @CRYPTO_LIBS@
+
+SUBDIRS =                      test
+
+EXTRA_DIST =                   $(srcdir)/*.h $(srcdir)/*.cpp
+
+# Compile with support of OpenSSL
+if WITH_OPENSSL
+libsofthsm_crypto_la_SOURCES +=        OSSLAES.cpp \
+                               OSSLComp.cpp \
+                               OSSLCryptoFactory.cpp \
+                               OSSLDES.cpp \
+                               OSSLDH.cpp \
+                               OSSLDHKeyPair.cpp \
+                               OSSLDHPrivateKey.cpp \
+                               OSSLDHPublicKey.cpp \
+                               OSSLDSA.cpp \
+                               OSSLDSAKeyPair.cpp \
+                               OSSLDSAPrivateKey.cpp \
+                               OSSLDSAPublicKey.cpp \
+                               OSSLECDH.cpp \
+                               OSSLECDSA.cpp \
+                               OSSLECKeyPair.cpp \
+                               OSSLECPrivateKey.cpp \
+                               OSSLECPublicKey.cpp \
+                               OSSLEVPHashAlgorithm.cpp \
+                               OSSLEVPMacAlgorithm.cpp \
+                               OSSLEVPCMacAlgorithm.cpp \
+                               OSSLEVPSymmetricAlgorithm.cpp \
+                               OSSLGOST.cpp \
+                               OSSLGOSTKeyPair.cpp \
+                               OSSLGOSTPrivateKey.cpp \
+                               OSSLGOSTPublicKey.cpp \
+                               OSSLGOSTR3411.cpp \
+                               OSSLCMAC.cpp \
+                               OSSLHMAC.cpp \
+                               OSSLMD5.cpp \
+                               OSSLRNG.cpp \
+                               OSSLRSA.cpp \
+                               OSSLRSAKeyPair.cpp \
+                               OSSLRSAPrivateKey.cpp \
+                               OSSLRSAPublicKey.cpp \
+                               OSSLSHA1.cpp \
+                               OSSLSHA224.cpp \
+                               OSSLSHA256.cpp \
+                               OSSLSHA384.cpp \
+                               OSSLSHA512.cpp \
+                               OSSLUtil.cpp
+endif
+
+# Compile with support of Botan
+if WITH_BOTAN
+libsofthsm_crypto_la_SOURCES +=        BotanAES.cpp \
+                               BotanCryptoFactory.cpp \
+                               BotanDES.cpp \
+                               BotanDH.cpp \
+                               BotanDHKeyPair.cpp \
+                               BotanDHPrivateKey.cpp \
+                               BotanDHPublicKey.cpp \
+                               BotanDSA.cpp \
+                               BotanDSAKeyPair.cpp \
+                               BotanDSAPrivateKey.cpp \
+                               BotanDSAPublicKey.cpp \
+                               BotanECDH.cpp \
+                               BotanECDHKeyPair.cpp \
+                               BotanECDHPrivateKey.cpp \
+                               BotanECDHPublicKey.cpp \
+                               BotanECDSA.cpp \
+                               BotanECDSAKeyPair.cpp \
+                               BotanECDSAPrivateKey.cpp \
+                               BotanECDSAPublicKey.cpp \
+                               BotanGOST.cpp \
+                               BotanGOSTKeyPair.cpp \
+                               BotanGOSTPrivateKey.cpp \
+                               BotanGOSTPublicKey.cpp \
+                               BotanGOSTR3411.cpp \
+                               BotanHashAlgorithm.cpp \
+                               BotanMAC.cpp \
+                               BotanMacAlgorithm.cpp \
+                               BotanMD5.cpp \
+                               BotanRNG.cpp \
+                               BotanRSA.cpp \
+                               BotanRSAKeyPair.cpp \
+                               BotanRSAPrivateKey.cpp \
+                               BotanRSAPublicKey.cpp \
+                               BotanSHA1.cpp \
+                               BotanSHA224.cpp \
+                               BotanSHA256.cpp \
+                               BotanSHA384.cpp \
+                               BotanSHA512.cpp \
+                               BotanSymmetricAlgorithm.cpp \
+                               BotanUtil.cpp \
+                               Botan_ecb.cpp
+endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLAES.cpp b/SoftHSMv2/src/lib/crypto/OSSLAES.cpp
new file mode 100644 (file)
index 0000000..fd92a3e
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLAES.cpp
+
+ OpenSSL AES implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLAES.h"
+#include <algorithm>
+#include <openssl/aes.h>
+#include "salloc.h"
+
+// Wrap/Unwrap keys
+#ifdef HAVE_AES_KEY_WRAP
+bool OSSLAES::wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out)
+{
+       // RFC 3394 input length checks do not apply to RFC 5649 mode with padding
+       if (mode == SymWrap::AES_KEYWRAP && !checkLength(in.size(), 16, "wrap"))
+               return false;
+
+       return wrapUnwrapKey(key, mode, in, out, 1);
+}
+#else
+bool OSSLAES::wrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       return false;
+}
+#endif
+
+#ifdef HAVE_AES_KEY_WRAP
+bool OSSLAES::unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out)
+{
+       // RFC 3394 algorithm produce at least 3 blocks of data
+       if ((mode == SymWrap::AES_KEYWRAP && !checkLength(in.size(), 24, "unwrap")) ||
+       // RFC 5649 algorithm produce at least 2 blocks of data
+           (mode == SymWrap::AES_KEYWRAP_PAD && !checkLength(in.size(), 16, "unwrap")))
+               return false;
+       return wrapUnwrapKey(key, mode, in, out, 0);
+}
+#else
+bool OSSLAES::unwrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       return false;
+}
+#endif
+
+#ifdef HAVE_AES_KEY_WRAP
+// RFC 3394 wrapping and all unwrapping algorithms require aligned blocks
+bool OSSLAES::checkLength(const int insize, const int minsize, const char * const operation) const
+{
+       if (insize < minsize)
+       {
+               ERROR_MSG("key data to %s too small", operation);
+               return false;
+       }
+       if ((insize % 8) != 0)
+       {
+               ERROR_MSG("key data to %s not aligned", operation);
+               return false;
+       }
+       return true;
+}
+
+const EVP_CIPHER* OSSLAES::getWrapCipher(const SymWrap::Type mode, const SymmetricKey* key) const
+{
+       if (key == NULL)
+               return NULL;
+
+       // Check currentKey bit length; AES only supports 128, 192 or 256 bit keys
+       if ((key->getBitLen() != 128) &&
+           (key->getBitLen() != 192) &&
+           (key->getBitLen() != 256))
+       {
+               ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen());
+
+               return NULL;
+       }
+
+#ifdef HAVE_AES_KEY_WRAP
+       // Determine the un/wrapping mode
+       if (mode == SymWrap::AES_KEYWRAP)
+       {
+               // RFC 3394 AES key wrap
+               switch(key->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_wrap();
+                       case 192:
+                               return EVP_aes_192_wrap();
+                       case 256:
+                               return EVP_aes_256_wrap();
+               };
+       }
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       if (mode == SymWrap::AES_KEYWRAP_PAD)
+       {
+               // RFC 5649 AES key wrap with pad
+               switch(key->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_wrap_pad();
+                       case 192:
+                               return EVP_aes_192_wrap_pad();
+                       case 256:
+                               return EVP_aes_256_wrap_pad();
+               };
+       }
+#endif
+
+       ERROR_MSG("unknown AES key wrap mode %i", mode);
+       return NULL;
+}
+
+// EVP wrapping/unwrapping
+// wrap = 1 -> wrapping
+// wrap = 0 -> unwrapping
+bool OSSLAES::wrapUnwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out, const int wrap) const
+{
+       const char *prefix = "";
+       if (wrap == 0)
+               prefix = "un";
+
+       // Determine the cipher method
+       const EVP_CIPHER* cipher = getWrapCipher(mode, key);
+       if (cipher == NULL)
+       {
+               ERROR_MSG("Failed to get EVP %swrap cipher", prefix);
+               return false;
+       }
+
+       // Allocate the EVP context
+       EVP_CIPHER_CTX* pWrapCTX = EVP_CIPHER_CTX_new();
+       if (pWrapCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_CIPHER_CTX");
+               return false;
+       }
+       EVP_CIPHER_CTX_set_flags(pWrapCTX, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+
+       int rv = EVP_CipherInit_ex(pWrapCTX, cipher, NULL, (unsigned char*) key->getKeyBits().const_byte_str(), NULL, wrap);
+       if (rv)
+               // Padding is handled by cipher mode separately
+               rv = EVP_CIPHER_CTX_set_padding(pWrapCTX, 0);
+       if (!rv)
+       {
+               ERROR_MSG("Failed to initialise EVP cipher %swrap operation", prefix);
+
+               EVP_CIPHER_CTX_free(pWrapCTX);
+               return false;
+       }
+
+       // 1 input byte could be expanded to two AES blocks
+       out.resize(in.size() + 2 * EVP_CIPHER_CTX_block_size(pWrapCTX) - 1);
+       int outLen = 0;
+       int curBlockLen = 0;
+       rv = EVP_CipherUpdate(pWrapCTX, &out[0], &curBlockLen, in.const_byte_str(), in.size());
+       if (rv == 1) {
+               outLen = curBlockLen;
+               rv = EVP_CipherFinal_ex(pWrapCTX, &out[0] + outLen, &curBlockLen);
+       }
+       if (rv != 1)
+       {
+               ERROR_MSG("Failed EVP %swrap operation", prefix);
+
+               EVP_CIPHER_CTX_free(pWrapCTX);
+               return false;
+       }
+       EVP_CIPHER_CTX_free(pWrapCTX);
+       outLen += curBlockLen;
+       out.resize(outLen);
+       return true;
+}
+#endif
+
+const EVP_CIPHER* OSSLAES::getCipher() const
+{
+       if (currentKey == NULL) return NULL;
+
+       // Check currentKey bit length; AES only supports 128, 192 or 256 bit keys
+       if ((currentKey->getBitLen() != 128) &&
+           (currentKey->getBitLen() != 192) &&
+            (currentKey->getBitLen() != 256))
+       {
+               ERROR_MSG("Invalid AES currentKey length (%d bits)", currentKey->getBitLen());
+
+               return NULL;
+       }
+
+       // Determine the cipher mode
+       if (currentCipherMode == SymMode::CBC)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_cbc();
+                       case 192:
+                               return EVP_aes_192_cbc();
+                       case 256:
+                               return EVP_aes_256_cbc();
+               };
+       }
+       else if (currentCipherMode == SymMode::ECB)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_ecb();
+                       case 192:
+                               return EVP_aes_192_ecb();
+                       case 256:
+                               return EVP_aes_256_ecb();
+               };
+       }
+       else if (currentCipherMode == SymMode::CTR)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_ctr();
+                       case 192:
+                               return EVP_aes_192_ctr();
+                       case 256:
+                               return EVP_aes_256_ctr();
+               };
+       }
+       else if (currentCipherMode == SymMode::GCM)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 128:
+                               return EVP_aes_128_gcm();
+                       case 192:
+                               return EVP_aes_192_gcm();
+                       case 256:
+                               return EVP_aes_256_gcm();
+               };
+       }
+
+       ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode);
+
+       return NULL;
+}
+
+size_t OSSLAES::getBlockSize() const
+{
+       // The block size is 128 bits
+       return 128 >> 3;
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLAES.h b/SoftHSMv2/src/lib/crypto/OSSLAES.h
new file mode 100644 (file)
index 0000000..6310f31
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLAES.h
+
+ OpenSSL AES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLAES_H
+#define _SOFTHSM_V2_OSSLAES_H
+
+#include <openssl/evp.h>
+#include <string>
+#include "config.h"
+#include "OSSLEVPSymmetricAlgorithm.h"
+
+class OSSLAES : public OSSLEVPSymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~OSSLAES() { }
+
+       // Wrap/Unwrap keys
+       virtual bool wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       virtual bool unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       // Return the block size
+       virtual size_t getBlockSize() const;
+
+protected:
+       // Return the right EVP cipher for the operation
+       virtual const EVP_CIPHER* getCipher() const;
+       const EVP_CIPHER* getWrapCipher(const SymWrap::Type mode, const SymmetricKey* key) const;
+       bool wrapUnwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out, const int wrap) const;
+       bool checkLength(const int insize, const int minsize, const char * const operation) const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLAES_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp b/SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp
new file mode 100644 (file)
index 0000000..554c308
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+/*****************************************************************************
+ OSSLHMAC.cpp
+
+ OpenSSL HMAC implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLCMAC.h"
+
+const EVP_CIPHER* OSSLCMACDES::getEVPCipher() const
+{
+       switch(currentKey->getBitLen())
+       {
+               case 56:
+                       ERROR_MSG("Only supporting 3DES");
+                       return NULL;
+               case 112:
+                       return EVP_des_ede_cbc();
+               case 168:
+                       return EVP_des_ede3_cbc();
+               default:
+                       break;
+       };
+
+       ERROR_MSG("Invalid DES bit len %i", currentKey->getBitLen());
+
+       return NULL;
+}
+
+size_t OSSLCMACDES::getMacSize() const
+{
+       return 8;
+}
+
+const EVP_CIPHER* OSSLCMACAES::getEVPCipher() const
+{
+       switch(currentKey->getBitLen())
+       {
+               case 128:
+                       return EVP_aes_128_cbc();
+               case 192:
+                       return EVP_aes_192_cbc();
+               case 256:
+                       return EVP_aes_256_cbc();
+               default:
+                       break;
+       };
+
+       ERROR_MSG("Invalid AES bit len %i", currentKey->getBitLen());
+
+       return NULL;
+}
+
+size_t OSSLCMACAES::getMacSize() const
+{
+       return 16;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLCMAC.h b/SoftHSMv2/src/lib/crypto/OSSLCMAC.h
new file mode 100644 (file)
index 0000000..8d15e7c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+/*****************************************************************************
+ OSSLCMAC.h
+
+ OpenSSL CMAC implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLCMAC_H
+#define _SOFTHSM_V2_OSSLCMAC_H
+
+#include "config.h"
+#include "OSSLEVPCMacAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLCMACDES : public OSSLEVPCMacAlgorithm
+{
+protected:
+       virtual const EVP_CIPHER* getEVPCipher() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLCMACAES : public OSSLEVPCMacAlgorithm
+{
+protected:
+       virtual const EVP_CIPHER* getEVPCipher() const;
+       virtual size_t getMacSize() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLHMAC_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLComp.cpp b/SoftHSMv2/src/lib/crypto/OSSLComp.cpp
new file mode 100644 (file)
index 0000000..ede710b
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+/*****************************************************************************
+ OSSLUtil.cpp
+
+ Adding OpenSSL forward-compatible code as suggested by OpenSSL
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLComp.h"
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+/*
+ * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#ifdef WITH_ECC
+#include <openssl/ecdsa.h>
+#endif
+#include <openssl/rsa.h>
+
+#include <string.h>
+
+// EVP digest routines
+EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+       EVP_MD_CTX *ctx = (EVP_MD_CTX*)OPENSSL_malloc(sizeof *ctx);
+
+       if (ctx)
+               EVP_MD_CTX_init(ctx);
+
+       return ctx;
+}
+
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+       if (ctx)
+       {
+               EVP_MD_CTX_cleanup(ctx);
+               OPENSSL_free(ctx);
+       }
+}
+
+// HMAC routines
+HMAC_CTX *HMAC_CTX_new(void)
+{
+       HMAC_CTX *ctx = (HMAC_CTX*)OPENSSL_malloc(sizeof(*ctx));
+       if (ctx == NULL) return NULL;
+
+       HMAC_CTX_init(ctx);
+
+       return ctx;
+}
+
+void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+       if (ctx == NULL) return;
+
+       HMAC_CTX_cleanup(ctx);
+       OPENSSL_free(ctx);
+}
+
+// DH routines
+void DH_get0_pqg(const DH *dh,
+                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+       if (p != NULL)
+               *p = dh->p;
+       if (q != NULL)
+               *q = dh->q;
+       if (g != NULL)
+               *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+       /* If the fields p and g in d are NULL, the corresponding input
+        * parameters MUST be non-NULL.  q may remain NULL.
+        */
+       if ((dh->p == NULL && p == NULL)
+           || (dh->g == NULL && g == NULL))
+               return 0;
+
+       if (p != NULL)
+       {
+               BN_free(dh->p);
+               dh->p = p;
+       }
+       if (q != NULL)
+       {
+               BN_free(dh->q);
+               dh->q = q;
+       }
+       if (g != NULL)
+       {
+               BN_free(dh->g);
+               dh->g = g;
+       }
+
+       if (q != NULL)
+       {
+               dh->length = BN_num_bits(q);
+       }
+
+       return 1;
+}
+
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+       if (pub_key != NULL)
+               *pub_key = dh->pub_key;
+       if (priv_key != NULL)
+               *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+       /* If the field pub_key in dh is NULL, the corresponding input
+        * parameters MUST be non-NULL.  The priv_key field may
+        * be left NULL.
+        */
+       if (dh->pub_key == NULL && pub_key == NULL)
+               return 0;
+
+       if (pub_key != NULL)
+       {
+               BN_free(dh->pub_key);
+               dh->pub_key = pub_key;
+       }
+       if (priv_key != NULL)
+       {
+               BN_free(dh->priv_key);
+               dh->priv_key = priv_key;
+       }
+
+       return 1;
+}
+
+long DH_get_length(const DH *dh)
+{
+       return dh->length;
+}
+
+int DH_set_length(DH *dh, long length)
+{
+       dh->length = length;
+
+       return 1;
+}
+
+// DSA routines
+void DSA_get0_pqg(const DSA *d,
+                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+       if (p != NULL)
+               *p = d->p;
+       if (q != NULL)
+               *q = d->q;
+       if (g != NULL)
+               *g = d->g;
+}
+
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+       /* If the fields p, q and g in d are NULL, the corresponding input
+        * parameters MUST be non-NULL.
+        */
+       if ((d->p == NULL && p == NULL)
+           || (d->q == NULL && q == NULL)
+           || (d->g == NULL && g == NULL))
+               return 0;
+
+       if (p != NULL)
+       {
+               BN_free(d->p);
+               d->p = p;
+       }
+       if (q != NULL)
+       {
+               BN_free(d->q);
+               d->q = q;
+       }
+       if (g != NULL)
+       {
+               BN_free(d->g);
+               d->g = g;
+       }
+
+       return 1;
+}
+
+void DSA_get0_key(const DSA *d,
+                  const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+       if (pub_key != NULL)
+               *pub_key = d->pub_key;
+       if (priv_key != NULL)
+               *priv_key = d->priv_key;
+}
+
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+       /* If the field pub_key in d is NULL, the corresponding input
+        * parameters MUST be non-NULL.  The priv_key field may
+        * be left NULL.
+        */
+       if (d->pub_key == NULL && pub_key == NULL)
+               return 0;
+
+       if (pub_key != NULL)
+       {
+               BN_free(d->pub_key);
+               d->pub_key = pub_key;
+       }
+       if (priv_key != NULL)
+       {
+               BN_free(d->priv_key);
+               d->priv_key = priv_key;
+       }
+
+       return 1;
+}
+
+// DSA_SIG routines
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+       if (pr != NULL)
+               *pr = sig->r;
+       if (ps != NULL)
+               *ps = sig->s;
+}
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+       if (r == NULL || s == NULL)
+               return 0;
+       BN_clear_free(sig->r);
+       BN_clear_free(sig->s);
+       sig->r = r;
+       sig->s = s;
+       return 1;
+}
+
+// ECDSA_SIG routines
+#ifdef WITH_ECC
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+       if (pr != NULL)
+               *pr = sig->r;
+       if (ps != NULL)
+               *ps = sig->s;
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+       if (r == NULL || s == NULL)
+               return 0;
+       BN_clear_free(sig->r);
+       BN_clear_free(sig->s);
+       sig->r = r;
+       sig->s = s;
+
+       return 1;
+}
+#endif
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+       /* If the fields n and e in r are NULL, the corresponding input
+        * parameters MUST be non-NULL for n and e.  d may be
+        * left NULL (in case only the public key is used).
+        */
+       if ((r->n == NULL && n == NULL)
+           || (r->e == NULL && e == NULL))
+               return 0;
+
+       if (n != NULL)
+       {
+               BN_free(r->n);
+               r->n = n;
+       }
+       if (e != NULL)
+       {
+               BN_free(r->e);
+               r->e = e;
+       }
+       if (d != NULL)
+       {
+               BN_free(r->d);
+               r->d = d;
+       }
+
+       return 1;
+}
+
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+       /* If the fields p and q in r are NULL, the corresponding input
+        * parameters MUST be non-NULL.
+        */
+       if ((r->p == NULL && p == NULL)
+           || (r->q == NULL && q == NULL))
+               return 0;
+
+       if (p != NULL)
+       {
+               BN_free(r->p);
+               r->p = p;
+       }
+       if (q != NULL)
+       {
+               BN_free(r->q);
+               r->q = q;
+       }
+
+       return 1;
+}
+
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+       /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
+        * parameters MUST be non-NULL.
+        */
+       if ((r->dmp1 == NULL && dmp1 == NULL)
+           || (r->dmq1 == NULL && dmq1 == NULL)
+           || (r->iqmp == NULL && iqmp == NULL))
+               return 0;
+
+       if (dmp1 != NULL)
+       {
+               BN_free(r->dmp1);
+               r->dmp1 = dmp1;
+       }
+       if (dmq1 != NULL)
+       {
+               BN_free(r->dmq1);
+               r->dmq1 = dmq1;
+       }
+       if (iqmp != NULL)
+       {
+               BN_free(r->iqmp);
+               r->iqmp = iqmp;
+       }
+
+       return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+       if (n != NULL)
+               *n = r->n;
+       if (e != NULL)
+               *e = r->e;
+       if (d != NULL)
+               *d = r->d;
+}
+
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+       if (p != NULL)
+               *p = r->p;
+       if (q != NULL)
+               *q = r->q;
+}
+
+void RSA_get0_crt_params(const RSA *r,
+                         const BIGNUM **dmp1, const BIGNUM **dmq1,
+                         const BIGNUM **iqmp)
+{
+       if (dmp1 != NULL)
+               *dmp1 = r->dmp1;
+       if (dmq1 != NULL)
+               *dmq1 = r->dmq1;
+       if (iqmp != NULL)
+               *iqmp = r->iqmp;
+}
+
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLComp.h b/SoftHSMv2/src/lib/crypto/OSSLComp.h
new file mode 100644 (file)
index 0000000..4bced32
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+/*****************************************************************************
+ OSSLComp.h
+
+ Adding OpenSSL forward-compatible code as suggested by OpenSSL
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLCOMP_H
+#define _SOFTHSM_V2_OSSLCOMP_H
+
+#include "config.h"
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#ifdef WITH_ECC
+#include <openssl/ecdsa.h>
+#endif
+#include <openssl/rsa.h>
+
+// EVP digest routines
+EVP_MD_CTX *EVP_MD_CTX_new(void);
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
+
+// HMAC routines
+HMAC_CTX *HMAC_CTX_new(void);
+void HMAC_CTX_free(HMAC_CTX *ctx);
+
+// DH routines
+void DH_get0_pqg(const DH *dh,
+                const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key);
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+long DH_get_length(const DH *dh);
+int DH_set_length(DH *dh, long length);
+
+// DSA routines
+void DSA_get0_pqg(const DSA *d,
+                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DSA_get0_key(const DSA *d,
+                 const BIGNUM **pub_key, const BIGNUM **priv_key);
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+
+// DSA_SIG routines
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+// ECDSA_SIG routines
+#ifdef WITH_ECC
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+#endif
+
+// RSA routines
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+void RSA_get0_key(const RSA *r,
+                 const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+void RSA_get0_crt_params(const RSA *r,
+                        const BIGNUM **dmp1, const BIGNUM **dmq1,
+                        const BIGNUM **iqmp);
+
+#endif
+
+#endif // !_SOFTHSM_V2_OSSLCOMP_H
diff --git a/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp b/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp
new file mode 100644 (file)
index 0000000..ad27482
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLCryptoFactory.cpp
+
+ This is an OpenSSL based cryptographic algorithm factory
+ *****************************************************************************/
+
+#include "config.h"
+#include "MutexFactory.h"
+#include "OSSLCryptoFactory.h"
+#include "OSSLRNG.h"
+#include "OSSLAES.h"
+#include "OSSLDES.h"
+#include "OSSLMD5.h"
+#include "OSSLSHA1.h"
+#include "OSSLSHA224.h"
+#include "OSSLSHA256.h"
+#include "OSSLSHA384.h"
+#include "OSSLSHA512.h"
+#include "OSSLCMAC.h"
+#include "OSSLHMAC.h"
+#include "OSSLRSA.h"
+#include "OSSLDSA.h"
+#include "OSSLDH.h"
+#ifdef WITH_ECC
+#include "OSSLECDH.h"
+#include "OSSLECDSA.h"
+#endif
+#ifdef WITH_GOST
+#include "OSSLGOSTR3411.h"
+#include "OSSLGOST.h"
+#endif
+
+#include <algorithm>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/ssl.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#ifdef WITH_GOST
+#include <openssl/objects.h>
+#endif
+
+#ifdef WITH_FIPS
+// Initialise the FIPS 140-2 selftest status
+bool OSSLCryptoFactory::FipsSelfTestStatus = false;
+#endif
+
+static unsigned nlocks;
+static Mutex** locks;
+
+// Mutex callback
+void lock_callback(int mode, int n, const char* file, int line)
+{
+       if ((unsigned) n >= nlocks)
+       {
+               ERROR_MSG("out of range [0..%u[ lock %d at %s:%d",
+                         nlocks, n, file, line);
+
+               return;
+       }
+
+       Mutex* mtx = locks[(unsigned) n];
+
+       if (mode & CRYPTO_LOCK)
+       {
+               mtx->lock();
+       }
+       else
+       {
+               mtx->unlock();
+       }
+}
+
+// Constructor
+OSSLCryptoFactory::OSSLCryptoFactory()
+{
+       // Multi-thread support
+       nlocks = CRYPTO_num_locks();
+       locks = new Mutex*[nlocks];
+       for (unsigned i = 0; i < nlocks; i++)
+       {
+               locks[i] = MutexFactory::i()->getMutex();
+       }
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       setLockingCallback = false;
+       if (CRYPTO_get_locking_callback() == NULL)
+       {
+               CRYPTO_set_locking_callback(lock_callback);
+               setLockingCallback = true;
+       }
+#endif
+
+#ifdef WITH_FIPS
+       // Already in FIPS mode on reenter (avoiding selftests)
+       if (!FIPS_mode())
+       {
+               FipsSelfTestStatus = false;
+               if (!FIPS_mode_set(1))
+               {
+                       ERROR_MSG("can't enter into FIPS mode");
+                       return;
+               }
+       } else {
+               // Undo RAND_cleanup()
+               RAND_init_fips();
+       }
+       FipsSelfTestStatus = true;
+#endif
+
+       // Initialise OpenSSL
+       OpenSSL_add_all_algorithms();
+
+       // Initialise the one-and-only RNG
+       rng = new OSSLRNG();
+
+#ifdef WITH_GOST
+       // Load engines
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       ENGINE_load_builtin_engines();
+#else
+       OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN |
+                           OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
+
+       // Initialise the GOST engine
+       eg = ENGINE_by_id("gost");
+       if (eg == NULL)
+       {
+               ERROR_MSG("can't get the GOST engine");
+               return;
+       }
+       if (ENGINE_init(eg) <= 0)
+       {
+               ENGINE_free(eg);
+               eg = NULL;
+               ERROR_MSG("can't initialize the GOST engine");
+               return;
+       }
+       // better than digest_gost
+       EVP_GOST_34_11 = ENGINE_get_digest(eg, NID_id_GostR3411_94);
+       if (EVP_GOST_34_11 == NULL)
+       {
+               ERROR_MSG("can't get the GOST digest");
+               goto err;
+       }
+       // from the openssl.cnf
+       if (ENGINE_register_pkey_asn1_meths(eg) <= 0)
+       {
+               ERROR_MSG("can't register ASN.1 for the GOST engine");
+               goto err;
+       }
+       if (ENGINE_ctrl_cmd_string(eg,
+                                  "CRYPT_PARAMS",
+                                  "id-Gost28147-89-CryptoPro-A-ParamSet",
+                                  0) <= 0)
+       {
+               ERROR_MSG("can't set params of the GOST engine");
+               goto err;
+       }
+       return;
+
+err:
+       ENGINE_finish(eg);
+       ENGINE_free(eg);
+       eg = NULL;
+       return;
+#endif
+}
+
+// Destructor
+OSSLCryptoFactory::~OSSLCryptoFactory()
+{
+#ifdef WITH_GOST
+       // Finish the GOST engine
+       if (eg != NULL)
+       {
+               ENGINE_finish(eg);
+               ENGINE_free(eg);
+               eg = NULL;
+       }
+#endif
+
+       // Destroy the one-and-only RNG
+       delete rng;
+
+       // Recycle locks
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       if (setLockingCallback)
+       {
+               CRYPTO_set_locking_callback(NULL);
+       }
+#endif
+       for (unsigned i = 0; i < nlocks; i++)
+       {
+               MutexFactory::i()->recycleMutex(locks[i]);
+       }
+       delete[] locks;
+}
+
+// Return the one-and-only instance
+OSSLCryptoFactory* OSSLCryptoFactory::i()
+{
+       if (!instance.get())
+       {
+               instance.reset(new OSSLCryptoFactory());
+       }
+
+       return instance.get();
+}
+
+// This will destroy the one-and-only instance.
+void OSSLCryptoFactory::reset()
+{
+       instance.reset();
+}
+
+#ifdef WITH_FIPS
+bool OSSLCryptoFactory::getFipsSelfTestStatus() const
+{
+       return FipsSelfTestStatus;
+}
+#endif
+
+// Create a concrete instance of a symmetric algorithm
+SymmetricAlgorithm* OSSLCryptoFactory::getSymmetricAlgorithm(SymAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case SymAlgo::AES:
+                       return new OSSLAES();
+               case SymAlgo::DES:
+               case SymAlgo::DES3:
+                       return new OSSLDES();
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of an asymmetric algorithm
+AsymmetricAlgorithm* OSSLCryptoFactory::getAsymmetricAlgorithm(AsymAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case AsymAlgo::RSA:
+                       return new OSSLRSA();
+               case AsymAlgo::DSA:
+                       return new OSSLDSA();
+               case AsymAlgo::DH:
+                       return new OSSLDH();
+#ifdef WITH_ECC
+               case AsymAlgo::ECDH:
+                       return new OSSLECDH();
+               case AsymAlgo::ECDSA:
+                       return new OSSLECDSA();
+#endif
+#ifdef WITH_GOST
+               case AsymAlgo::GOST:
+                       return new OSSLGOST();
+#endif
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of a hash algorithm
+HashAlgorithm* OSSLCryptoFactory::getHashAlgorithm(HashAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case HashAlgo::MD5:
+                       return new OSSLMD5();
+               case HashAlgo::SHA1:
+                       return new OSSLSHA1();
+               case HashAlgo::SHA224:
+                       return new OSSLSHA224();
+               case HashAlgo::SHA256:
+                       return new OSSLSHA256();
+               case HashAlgo::SHA384:
+                       return new OSSLSHA384();
+               case HashAlgo::SHA512:
+                       return new OSSLSHA512();
+#ifdef WITH_GOST
+               case HashAlgo::GOST:
+                       return new OSSLGOSTR3411();
+#endif
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Create a concrete instance of a MAC algorithm
+MacAlgorithm* OSSLCryptoFactory::getMacAlgorithm(MacAlgo::Type algorithm)
+{
+       switch (algorithm)
+       {
+               case MacAlgo::HMAC_MD5:
+                       return new OSSLHMACMD5();
+               case MacAlgo::HMAC_SHA1:
+                       return new OSSLHMACSHA1();
+               case MacAlgo::HMAC_SHA224:
+                       return new OSSLHMACSHA224();
+               case MacAlgo::HMAC_SHA256:
+                       return new OSSLHMACSHA256();
+               case MacAlgo::HMAC_SHA384:
+                       return new OSSLHMACSHA384();
+               case MacAlgo::HMAC_SHA512:
+                       return new OSSLHMACSHA512();
+#ifdef WITH_GOST
+               case MacAlgo::HMAC_GOST:
+                       return new OSSLHMACGOSTR3411();
+#endif
+               case MacAlgo::CMAC_DES:
+                       return new OSSLCMACDES();
+               case MacAlgo::CMAC_AES:
+                       return new OSSLCMACAES();
+               default:
+                       // No algorithm implementation is available
+                       ERROR_MSG("Unknown algorithm '%i'", algorithm);
+
+                       return NULL;
+       }
+
+       // No algorithm implementation is available
+       return NULL;
+}
+
+// Get the global RNG (may be an unique RNG per thread)
+RNG* OSSLCryptoFactory::getRNG(RNGImpl::Type name /* = RNGImpl::Default */)
+{
+       if (name == RNGImpl::Default)
+       {
+               return rng;
+       }
+       else
+       {
+               // No RNG implementation is available
+               ERROR_MSG("Unknown RNG '%i'", name);
+
+               return NULL;
+       }
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h b/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h
new file mode 100644 (file)
index 0000000..e8bfa2c
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ OSSLCryptoFactory.h
+
+ This is an OpenSSL based cryptographic algorithm factory
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLCRYPTOFACTORY_H
+#define _SOFTHSM_V2_OSSLCRYPTOFACTORY_H
+
+#include "config.h"
+#include "CryptoFactory.h"
+#include "SymmetricAlgorithm.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "RNG.h"
+#include <memory>
+#ifdef WITH_GOST
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#endif
+
+class OSSLCryptoFactory : public CryptoFactory
+{
+public:
+       // Return the one-and-only instance
+       static OSSLCryptoFactory* i();
+
+       // This will destroy the one-and-only instance.
+       static void reset();
+
+#ifdef WITH_FIPS
+       // Return the FIPS 140-2 selftest status
+       virtual bool getFipsSelfTestStatus() const;
+#endif
+
+       // Create a concrete instance of a symmetric algorithm
+       virtual SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type algorithm);
+
+       // Create a concrete instance of an asymmetric algorithm
+       virtual AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type algorithm);
+
+       // Create a concrete instance of a hash algorithm
+       virtual HashAlgorithm* getHashAlgorithm(HashAlgo::Type algorithm);
+
+       // Create a concrete instance of a MAC algorithm
+       virtual MacAlgorithm* getMacAlgorithm(MacAlgo::Type algorithm);
+
+       // Get the global RNG (may be an unique RNG per thread)
+       virtual RNG* getRNG(RNGImpl::Type name = RNGImpl::Default);
+
+       // Destructor
+       virtual ~OSSLCryptoFactory();
+
+#ifdef WITH_GOST
+       // The EVP_MD for GOST R 34.11-94
+       const EVP_MD *EVP_GOST_34_11;
+#endif
+
+private:
+       // Constructor
+       OSSLCryptoFactory();
+
+       // The one-and-only instance
+#ifdef HAVE_CXX11
+       static std::unique_ptr<OSSLCryptoFactory> instance;
+#else
+       static std::auto_ptr<OSSLCryptoFactory> instance;
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       bool setLockingCallback;
+#endif
+
+#ifdef WITH_FIPS
+       // The FIPS 140-2 selftest status
+       static bool FipsSelfTestStatus;
+#endif
+
+       // The one-and-only RNG instance
+       RNG* rng;
+
+#ifdef WITH_GOST
+       // The GOST engine
+       ENGINE *eg;
+#endif
+};
+
+#endif // !_SOFTHSM_V2_OSSLCRYPTOFACTORY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDES.cpp b/SoftHSMv2/src/lib/crypto/OSSLDES.cpp
new file mode 100644 (file)
index 0000000..4fb56b5
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDES.cpp
+
+ OpenSSL (3)DES implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLDES.h"
+#include <algorithm>
+#include "odd.h"
+
+bool OSSLDES::wrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       ERROR_MSG("DES does not support key wrapping");
+
+       return false;
+}
+
+bool OSSLDES::unwrapKey(const SymmetricKey* /*key*/, const SymWrap::Type /*mode*/, const ByteString& /*in*/, ByteString& /*out*/)
+{
+       ERROR_MSG("DES does not support key unwrapping");
+
+       return false;
+}
+
+const EVP_CIPHER* OSSLDES::getCipher() const
+{
+       if (currentKey == NULL) return NULL;
+
+       // Check currentKey bit length; 3DES only supports 56-bit, 112-bit or 168-bit keys 
+       if (
+#ifndef WITH_FIPS
+           (currentKey->getBitLen() != 56) &&
+#endif
+           (currentKey->getBitLen() != 112) &&
+            (currentKey->getBitLen() != 168))
+       {
+               ERROR_MSG("Invalid DES currentKey length (%d bits)", currentKey->getBitLen());
+
+               return NULL;
+       }
+
+       // People shouldn't really be using 56-bit DES keys, generate a warning
+       if (currentKey->getBitLen() == 56)
+       {
+               DEBUG_MSG("CAUTION: use of 56-bit DES keys is not recommended!");
+       }
+
+       // Determine the cipher mode
+       if (currentCipherMode == SymMode::CBC)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 56:
+                               return EVP_des_cbc();
+                       case 112:
+                               return EVP_des_ede_cbc();
+                       case 168:
+                               return EVP_des_ede3_cbc();
+               };
+       }
+       else if (currentCipherMode == SymMode::ECB)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 56:
+                               return EVP_des_ecb();
+                       case 112:
+                               return EVP_des_ede_ecb();
+                       case 168:
+                               return EVP_des_ede3_ecb();
+               };
+       }
+       else if (currentCipherMode == SymMode::OFB)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 56:
+                               return EVP_des_ofb();
+                       case 112:
+                               return EVP_des_ede_ofb();
+                       case 168:
+                               return EVP_des_ede3_ofb();
+               };
+       }
+       else if (currentCipherMode == SymMode::CFB)
+       {
+               switch(currentKey->getBitLen())
+               {
+                       case 56:
+                               return EVP_des_cfb();
+                       case 112:
+                               return EVP_des_ede_cfb();
+                       case 168:
+                               return EVP_des_ede3_cfb();
+               };
+       }
+
+       ERROR_MSG("Invalid DES cipher mode %i", currentCipherMode);
+
+       return NULL;
+}
+
+bool OSSLDES::generateKey(SymmetricKey& key, RNG* rng /* = NULL */)
+{
+       if (rng == NULL)
+       {
+               return false;
+       }
+
+       if (key.getBitLen() == 0)
+       {
+               return false;
+       }
+
+       ByteString keyBits;
+
+       // don't count parity bit
+       if (!rng->generateRandom(keyBits, key.getBitLen()/7))
+       {
+               return false;
+       }
+
+       // fix the odd parity
+       size_t i;
+       for (i = 0; i < keyBits.size(); i++)
+       {
+               keyBits[i] = odd_parity[keyBits[i]];
+       }
+
+       return key.setKeyBits(keyBits);
+}
+
+size_t OSSLDES::getBlockSize() const
+{
+       // The block size is 64 bits
+       return 64 >> 3;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDES.h b/SoftHSMv2/src/lib/crypto/OSSLDES.h
new file mode 100644 (file)
index 0000000..1ecdc8c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDES.h
+
+ OpenSSL AES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDES_H
+#define _SOFTHSM_V2_OSSLDES_H
+
+#include <openssl/evp.h>
+#include <string>
+#include "config.h"
+#include "OSSLEVPSymmetricAlgorithm.h"
+
+class OSSLDES : public OSSLEVPSymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~OSSLDES() { }
+
+       // Wrap/Unwrap keys
+       virtual bool wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       virtual bool unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out);
+
+       // Generate key
+       virtual bool generateKey(SymmetricKey& key, RNG* rng = NULL);
+
+       // Return the block size
+       virtual size_t getBlockSize() const;
+
+protected:
+       // Return the right EVP cipher for the operation
+       virtual const EVP_CIPHER* getCipher() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDES_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDH.cpp b/SoftHSMv2/src/lib/crypto/OSSLDH.cpp
new file mode 100644 (file)
index 0000000..ee61733
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDH.cpp
+
+ OpenSSL Diffie-Hellman asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDH.h"
+#include "CryptoFactory.h"
+#include "DHParameters.h"
+#include "OSSLComp.h"
+#include "OSSLDHKeyPair.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/dh.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+// Signing functions
+bool OSSLDH::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                     const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+bool OSSLDH::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+bool OSSLDH::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("DH does not support signing");
+
+       return false;
+}
+
+// Verification functions
+bool OSSLDH::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                       const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+bool OSSLDH::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+bool OSSLDH::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("DH does not support verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool OSSLDH::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                    ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DH does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool OSSLDH::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                    ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DH does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool OSSLDH::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(DHParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for DH key generation");
+
+               return false;
+       }
+
+       DHParameters* params = (DHParameters*) parameters;
+
+       // Generate the key-pair
+       DH* dh = DH_new();
+       if (dh == NULL)
+       {
+               ERROR_MSG("Failed to instantiate OpenSSL DH object");
+
+               return false;
+       }
+
+       BIGNUM* bn_p = OSSL::byteString2bn(params->getP());
+       BIGNUM* bn_g = OSSL::byteString2bn(params->getG());
+
+       if (!DH_set0_pqg(dh, bn_p, NULL, bn_g))
+       {
+               ERROR_MSG("DH set pqg failed (0x%08X)", ERR_get_error());
+
+               BN_free(bn_p);
+               BN_free(bn_g);
+               DH_free(dh);
+
+               return false;
+       }
+
+       if (params->getXBitLength() > 0)
+       {
+               if (!DH_set_length(dh, params->getXBitLength()))
+               {
+                       ERROR_MSG("DH set length failed (0x%08X)", ERR_get_error());
+
+                       DH_free(dh);
+
+                       return false;
+               }
+       }
+
+       if (DH_generate_key(dh) != 1)
+       {
+               ERROR_MSG("DH key generation failed (0x%08X)", ERR_get_error());
+
+               DH_free(dh);
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       OSSLDHKeyPair* kp = new OSSLDHKeyPair();
+
+       ((OSSLDHPublicKey*) kp->getPublicKey())->setFromOSSL(dh);
+       ((OSSLDHPrivateKey*) kp->getPrivateKey())->setFromOSSL(dh);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       DH_free(dh);
+
+       return true;
+}
+
+bool OSSLDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
+{
+       // Check parameters
+       if ((ppSymmetricKey == NULL) ||
+           (publicKey == NULL) ||
+           (privateKey == NULL))
+       {
+               return false;
+       }
+
+       // Get keys
+       DH *pub = ((OSSLDHPublicKey *)publicKey)->getOSSLKey();
+       DH *priv = ((OSSLDHPrivateKey *)privateKey)->getOSSLKey();
+       if (pub == NULL || priv == NULL)
+       {
+               ERROR_MSG("Failed to get OpenSSL DH keys");
+
+               return false;
+       }
+       const BIGNUM* bn_pub_key = NULL;
+       DH_get0_key(pub, &bn_pub_key, NULL);
+       if (bn_pub_key == NULL)
+       {
+               ERROR_MSG("Failed to get OpenSSL DH keys");
+
+               return false;
+       }
+
+       // Derive the secret
+       ByteString secret, derivedSecret;
+       int size = DH_size(priv);
+       secret.wipe(size);
+       derivedSecret.wipe(size);
+       int keySize = DH_compute_key(&derivedSecret[0], bn_pub_key, priv);
+
+       if (keySize <= 0)
+       {
+               ERROR_MSG("DH key derivation failed (0x%08X)", ERR_get_error());
+
+               return false;
+       }
+
+       // We compensate that OpenSSL removes leading zeros
+       memcpy(&secret[0] + size - keySize, &derivedSecret[0], keySize);
+
+       *ppSymmetricKey = new SymmetricKey(secret.size() * 8);
+       if (*ppSymmetricKey == NULL)
+               return false;
+       if (!(*ppSymmetricKey)->setKeyBits(secret))
+       {
+               delete *ppSymmetricKey;
+               *ppSymmetricKey = NULL;
+               return false;
+       }
+
+       return true;
+}
+
+unsigned long OSSLDH::getMinKeySize()
+{
+#ifdef WITH_FIPS
+       // OPENSSL_DH_FIPS_MIN_MODULUS_BITS is 1024
+       return 1024;
+#else
+       return 512;
+#endif
+}
+
+unsigned long OSSLDH::getMaxKeySize()
+{
+       return OPENSSL_DH_MAX_MODULUS_BITS;
+}
+
+bool OSSLDH::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
+{
+       if ((ppParams == NULL) || (parameters == NULL))
+       {
+               return false;
+       }
+
+       size_t bitLen = (size_t) parameters;
+
+       if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
+       {
+               ERROR_MSG("This DH key size is not supported");
+
+               return false;
+       }
+
+       DH* dh = DH_new();
+       if (dh == NULL)
+       {
+               ERROR_MSG("Failed to create DH object");
+
+               return false;
+       }
+
+       if (!DH_generate_parameters_ex(dh, bitLen, 2, NULL))
+       {
+               ERROR_MSG("Failed to generate %d bit DH parameters", bitLen);
+
+               DH_free(dh);
+
+               return false;
+       }
+
+       // Store the DH parameters
+       DHParameters* params = new DHParameters();
+
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_g = NULL;
+
+       DH_get0_pqg(dh, &bn_p, NULL, &bn_g);
+       ByteString p = OSSL::bn2ByteString(bn_p); params->setP(p);
+       ByteString g = OSSL::bn2ByteString(bn_g); params->setG(g);
+
+       *ppParams = params;
+
+       DH_free(dh);
+
+       return true;
+}
+
+bool OSSLDH::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLDHKeyPair* kp = new OSSLDHKeyPair();
+
+       bool rv = true;
+
+       if (!((DHPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((DHPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLDH::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLDHPublicKey* pub = new OSSLDHPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLDH::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLDHPrivateKey* priv = new OSSLDHPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLDH::newPublicKey()
+{
+       return (PublicKey*) new OSSLDHPublicKey();
+}
+
+PrivateKey* OSSLDH::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLDHPrivateKey();
+}
+
+AsymmetricParameters* OSSLDH::newParameters()
+{
+       return (AsymmetricParameters*) new DHParameters();
+}
+
+bool OSSLDH::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       DHParameters* params = new DHParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDH.h b/SoftHSMv2/src/lib/crypto/OSSLDH.h
new file mode 100644 (file)
index 0000000..d611aee
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDH.h
+
+ OpenSSL Diffie-Hellman asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDH_H
+#define _SOFTHSM_V2_OSSLDH_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <openssl/dh.h>
+
+class OSSLDH : public AsymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~OSSLDH() { }
+
+       // Signing functions
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool generateParameters(AsymmetricParameters** ppParams, void* parameters = NULL, RNG* rng = NULL);
+       virtual bool deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_OSSLDH_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp b/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp
new file mode 100644 (file)
index 0000000..4865553
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHKeyPair.cpp
+
+ OpenSSL Diffie-Hellman key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDHKeyPair.h"
+
+// Set the public key
+void OSSLDHKeyPair::setPublicKey(OSSLDHPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void OSSLDHKeyPair::setPrivateKey(OSSLDHPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* OSSLDHKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* OSSLDHKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* OSSLDHKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* OSSLDHKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h b/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h
new file mode 100644 (file)
index 0000000..320d5ab
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHKeyPair.h
+
+ OpenSSL Diffie-Hellman key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDHKEYPAIR_H
+#define _SOFTHSM_V2_OSSLDHKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "OSSLDHPublicKey.h"
+#include "OSSLDHPrivateKey.h"
+
+class OSSLDHKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(OSSLDHPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(OSSLDHPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       OSSLDHPublicKey pubKey;
+
+       // The private key
+       OSSLDHPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDHKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp
new file mode 100644 (file)
index 0000000..5571a88
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHPrivateKey.cpp
+
+ OpenSSL Diffie-Hellman private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLComp.h"
+#include "OSSLDHPrivateKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Constructors
+OSSLDHPrivateKey::OSSLDHPrivateKey()
+{
+       dh = NULL;
+}
+
+OSSLDHPrivateKey::OSSLDHPrivateKey(const DH* inDH)
+{
+       dh = NULL;
+
+       setFromOSSL(inDH);
+}
+
+// Destructor
+OSSLDHPrivateKey::~OSSLDHPrivateKey()
+{
+       DH_free(dh);
+}
+
+// The type
+/*static*/ const char* OSSLDHPrivateKey::type = "OpenSSL DH Private Key";
+
+// Set from OpenSSL representation
+void OSSLDHPrivateKey::setFromOSSL(const DH* inDH)
+{
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_g = NULL;
+       const BIGNUM* bn_priv_key = NULL;
+
+       DH_get0_pqg(inDH, &bn_p, NULL, &bn_g);
+       DH_get0_key(inDH, NULL, &bn_priv_key);
+
+       if (bn_p)
+       {
+               ByteString inP = OSSL::bn2ByteString(bn_p);
+               setP(inP);
+       }
+       if (bn_g)
+       {
+               ByteString inG = OSSL::bn2ByteString(bn_g);
+               setG(inG);
+       }
+       if (bn_priv_key)
+       {
+               ByteString inX = OSSL::bn2ByteString(bn_priv_key);
+               setX(inX);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLDHPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DH private key components
+void OSSLDHPrivateKey::setX(const ByteString& inX)
+{
+       DHPrivateKey::setX(inX);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+
+// Setters for the DH public key components
+void OSSLDHPrivateKey::setP(const ByteString& inP)
+{
+       DHPrivateKey::setP(inP);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+void OSSLDHPrivateKey::setG(const ByteString& inG)
+{
+       DHPrivateKey::setG(inG);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString OSSLDHPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       if (dh == NULL) createOSSLKey();
+       if (dh == NULL) return der;
+       EVP_PKEY* pkey = EVP_PKEY_new();
+       if (pkey == NULL) return der;
+       if (!EVP_PKEY_set1_DH(pkey, dh))
+       {
+               EVP_PKEY_free(pkey);
+               return der;
+       }
+       PKCS8_PRIV_KEY_INFO* p8inf = EVP_PKEY2PKCS8(pkey);
+       EVP_PKEY_free(pkey);
+       if (p8inf == NULL) return der;
+       int len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, NULL);
+       if (len < 0)
+       {
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return der;
+       }
+       der.resize(len);
+       unsigned char* priv = &der[0];
+       int len2 = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &priv);
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       if (len2 != len) der.wipe();
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool OSSLDHPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       int len = ber.size();
+       if (len <= 0) return false;
+       const unsigned char* priv = ber.const_byte_str();
+       PKCS8_PRIV_KEY_INFO* p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &priv, len);
+       if (p8 == NULL) return false;
+       EVP_PKEY* pkey = EVP_PKCS82PKEY(p8);
+       PKCS8_PRIV_KEY_INFO_free(p8);
+       if (pkey == NULL) return false;
+       DH* key = EVP_PKEY_get1_DH(pkey);
+       EVP_PKEY_free(pkey);
+       if (key == NULL) return false;
+       setFromOSSL(key);
+       DH_free(key);
+       return true;
+}
+
+// Retrieve the OpenSSL representation of the key
+DH* OSSLDHPrivateKey::getOSSLKey()
+{
+       if (dh == NULL) createOSSLKey();
+
+       return dh;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLDHPrivateKey::createOSSLKey()
+{
+       if (dh != NULL) return;
+
+       BN_CTX *ctx = BN_CTX_new();
+       if (ctx == NULL)
+       {
+               ERROR_MSG("Could not create BN_CTX");
+               return;
+       }
+
+       dh = DH_new();
+       if (dh == NULL)
+       {
+               ERROR_MSG("Could not create DH object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               DH_set_method(dh, FIPS_dh_openssl());
+       else
+               DH_set_method(dh, DH_OpenSSL());
+#else
+       DH_set_method(dh, DH_OpenSSL());
+#endif
+
+#else
+       DH_set_method(dh, DH_OpenSSL());
+#endif
+
+       BIGNUM* bn_p = OSSL::byteString2bn(p);
+       BIGNUM* bn_g = OSSL::byteString2bn(g);
+       BIGNUM* bn_priv_key = OSSL::byteString2bn(x);
+       BIGNUM* bn_pub_key = BN_new();
+
+       BN_mod_exp(bn_pub_key, bn_g, bn_priv_key, bn_p, ctx);
+       BN_CTX_free(ctx);
+
+       DH_set0_pqg(dh, bn_p, NULL, bn_g);
+       DH_set0_key(dh, bn_pub_key, bn_priv_key);
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h b/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h
new file mode 100644 (file)
index 0000000..2cf8599
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHPrivateKey.h
+
+ OpenSSL Diffie-Hellman private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDHPRIVATEKEY_H
+#define _SOFTHSM_V2_OSSLDHPRIVATEKEY_H
+
+#include "config.h"
+#include "DHPrivateKey.h"
+#include <openssl/dh.h>
+
+class OSSLDHPrivateKey : public DHPrivateKey
+{
+public:
+       // Constructors
+       OSSLDHPrivateKey();
+
+       OSSLDHPrivateKey(const DH* inDH);
+
+       // Destructor
+       virtual ~OSSLDHPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DH private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const DH* inDH);
+
+       // Retrieve the OpenSSL representation of the key
+       DH* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       DH* dh;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLDHPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp
new file mode 100644 (file)
index 0000000..e261726
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHPublicKey.cpp
+
+ OpenSSL Diffie-Hellman public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLComp.h"
+#include "OSSLDHPublicKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Constructors
+OSSLDHPublicKey::OSSLDHPublicKey()
+{
+       dh = NULL;
+}
+
+OSSLDHPublicKey::OSSLDHPublicKey(const DH* inDH)
+{
+       dh = NULL;
+
+       setFromOSSL(inDH);
+}
+
+// Destructor
+OSSLDHPublicKey::~OSSLDHPublicKey()
+{
+       DH_free(dh);
+}
+
+// The type
+/*static*/ const char* OSSLDHPublicKey::type = "OpenSSL DH Public Key";
+
+// Set from OpenSSL representation
+void OSSLDHPublicKey::setFromOSSL(const DH* inDH)
+{
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_g = NULL;
+       const BIGNUM* bn_pub_key = NULL;
+
+       DH_get0_pqg(inDH, &bn_p, NULL, &bn_g);
+       DH_get0_key(inDH, &bn_pub_key, NULL);
+
+       if (bn_p)
+       {
+               ByteString inP = OSSL::bn2ByteString(bn_p);
+               setP(inP);
+       }
+       if (bn_g)
+       {
+               ByteString inG = OSSL::bn2ByteString(bn_g);
+               setG(inG);
+       }
+       if (bn_pub_key)
+       {
+               ByteString inY = OSSL::bn2ByteString(bn_pub_key);
+               setY(inY);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLDHPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DH public key components
+void OSSLDHPublicKey::setP(const ByteString& inP)
+{
+       DHPublicKey::setP(inP);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+void OSSLDHPublicKey::setG(const ByteString& inG)
+{
+       DHPublicKey::setG(inG);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+void OSSLDHPublicKey::setY(const ByteString& inY)
+{
+       DHPublicKey::setY(inY);
+
+       if (dh)
+       {
+               DH_free(dh);
+               dh = NULL;
+       }
+}
+
+// Retrieve the OpenSSL representation of the key
+DH* OSSLDHPublicKey::getOSSLKey()
+{
+       if (dh == NULL) createOSSLKey();
+
+       return dh;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLDHPublicKey::createOSSLKey()
+{
+       if (dh != NULL) return;
+
+       dh = DH_new();
+       if (dh == NULL)
+       {
+               ERROR_MSG("Could not create DH object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               DH_set_method(dh, FIPS_dh_openssl());
+       else
+               DH_set_method(dh, DH_OpenSSL());
+#else
+       DH_set_method(dh, DH_OpenSSL());
+#endif
+
+#else
+       DH_set_method(dh, DH_OpenSSL());
+#endif
+
+       BIGNUM* bn_p = OSSL::byteString2bn(p);
+       BIGNUM* bn_g = OSSL::byteString2bn(g);
+       BIGNUM* bn_pub_key = OSSL::byteString2bn(y);
+
+       DH_set0_pqg(dh, bn_p, NULL, bn_g);
+       DH_set0_key(dh, bn_pub_key, NULL);
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h b/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h
new file mode 100644 (file)
index 0000000..9f5eed8
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDHPublicKey.h
+
+ OpenSSL Diffie-Hellman public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDHPUBLICKEY_H
+#define _SOFTHSM_V2_OSSLDHPUBLICKEY_H
+
+#include "config.h"
+#include "DHPublicKey.h"
+#include <openssl/dh.h>
+
+class OSSLDHPublicKey : public DHPublicKey
+{
+public:
+       // Constructors
+       OSSLDHPublicKey();
+
+       OSSLDHPublicKey(const DH* inDH);
+
+       // Destructor
+       virtual ~OSSLDHPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DH public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const DH* inDH);
+
+       // Retrieve the OpenSSL representation of the key
+       DH* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       DH* dh;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLDHPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp b/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp
new file mode 100644 (file)
index 0000000..06b5d50
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSA.cpp
+
+ OpenSSL DSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDSA.h"
+#include "CryptoFactory.h"
+#include "DSAParameters.h"
+#include "OSSLDSAKeyPair.h"
+#include "OSSLComp.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/dsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+// Constructor
+OSSLDSA::OSSLDSA()
+{
+       pCurrentHash = NULL;
+}
+
+// Destructor
+OSSLDSA::~OSSLDSA()
+{
+       if (pCurrentHash != NULL)
+       {
+               delete pCurrentHash;
+       }
+}
+
+// Signing functions
+bool OSSLDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                  ByteString& signature, const AsymMech::Type mechanism,
+                  const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::DSA)
+       {
+               // Separate implementation for DSA signing without hash computation
+
+               // Check if the private key is the right type
+               if (!privateKey->isOfType(OSSLDSAPrivateKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               OSSLDSAPrivateKey* pk = (OSSLDSAPrivateKey*) privateKey;
+               DSA* dsa = pk->getOSSLKey();
+
+               // Perform the signature operation
+               unsigned int sigLen = pk->getOutputLength();
+               signature.resize(sigLen);
+               memset(&signature[0], 0, sigLen);
+               int dLen = dataToSign.size();
+               DSA_SIG* sig = DSA_do_sign(dataToSign.const_byte_str(), dLen, dsa);
+               if (sig == NULL)
+                       return false;
+               // Store the 2 values with padding
+               const BIGNUM* bn_r = NULL;
+               const BIGNUM* bn_s = NULL;
+               DSA_SIG_get0(sig, &bn_r, &bn_s);
+               BN_bn2bin(bn_r, &signature[sigLen / 2 - BN_num_bytes(bn_r)]);
+               BN_bn2bin(bn_s, &signature[sigLen - BN_num_bytes(bn_s)]);
+               DSA_SIG_free(sig);
+               return true;
+       }
+       else
+       {
+               // Call default implementation
+               return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLDSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                      const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(OSSLDSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       HashAlgo::Type hash = HashAlgo::Unknown;
+
+       switch (mechanism)
+       {
+               case AsymMech::DSA_SHA1:
+                       hash = HashAlgo::SHA1;
+                       break;
+               case AsymMech::DSA_SHA224:
+                       hash = HashAlgo::SHA224;
+                       break;
+               case AsymMech::DSA_SHA256:
+                       hash = HashAlgo::SHA256;
+                       break;
+               case AsymMech::DSA_SHA384:
+                       hash = HashAlgo::SHA384;
+                       break;
+               case AsymMech::DSA_SHA512:
+                       hash = HashAlgo::SHA512;
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+       }
+
+       pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash);
+
+       if (pCurrentHash == NULL)
+       {
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       if (!pCurrentHash->hashInit())
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLDSA::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       if (!pCurrentHash->hashUpdate(dataToSign))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLDSA::signFinal(ByteString& signature)
+{
+       // Save necessary state before calling super class signFinal
+       OSSLDSAPrivateKey* pk = (OSSLDSAPrivateKey*) currentPrivateKey;
+
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString hash;
+
+       bool bFirstResult = pCurrentHash->hashFinal(hash);
+
+       delete pCurrentHash;
+       pCurrentHash = NULL;
+
+       if (!bFirstResult)
+       {
+               return false;
+       }
+
+       DSA* dsa = pk->getOSSLKey();
+
+       // Perform the signature operation
+       unsigned int sigLen = pk->getOutputLength();
+       signature.resize(sigLen);
+       memset(&signature[0], 0, sigLen);
+       DSA_SIG* sig = DSA_do_sign(&hash[0], hash.size(), dsa);
+       if (sig == NULL)
+               return false;
+       // Store the 2 values with padding
+       const BIGNUM* bn_r = NULL;
+       const BIGNUM* bn_s = NULL;
+       DSA_SIG_get0(sig, &bn_r, &bn_s);
+       BN_bn2bin(bn_r, &signature[sigLen / 2 - BN_num_bytes(bn_r)]);
+       BN_bn2bin(bn_s, &signature[sigLen - BN_num_bytes(bn_s)]);
+       DSA_SIG_free(sig);
+       return true;
+}
+
+// Verification functions
+bool OSSLDSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                    const ByteString& signature, const AsymMech::Type mechanism,
+                    const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::DSA)
+       {
+               // Separate implementation for DSA verification without hash computation
+
+               // Check if the private key is the right type
+               if (!publicKey->isOfType(OSSLDSAPublicKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // Perform the verify operation
+               OSSLDSAPublicKey* pk = (OSSLDSAPublicKey*) publicKey;
+               unsigned int sigLen = pk->getOutputLength();
+               if (signature.size() != sigLen)
+                       return false;
+               DSA_SIG* sig = DSA_SIG_new();
+               if (sig == NULL)
+                       return false;
+               const unsigned char *s = signature.const_byte_str();
+               BIGNUM* bn_r = BN_bin2bn(s, sigLen / 2, NULL);
+               BIGNUM* bn_s = BN_bin2bn(s + sigLen / 2, sigLen / 2, NULL);
+               if (bn_r == NULL || bn_s == NULL ||
+                   !DSA_SIG_set0(sig, bn_r, bn_s))
+               {
+                       DSA_SIG_free(sig);
+                       return false;
+               }
+               int dLen = originalData.size();
+               int ret = DSA_do_verify(originalData.const_byte_str(), dLen, sig, pk->getOSSLKey());
+               if (ret != 1)
+               {
+                       if (ret < 0)
+                               ERROR_MSG("DSA verify failed (0x%08X)", ERR_get_error());
+
+                       DSA_SIG_free(sig);
+                       return false;
+               }
+
+               DSA_SIG_free(sig);
+               return true;
+       }
+       else
+       {
+               // Call the generic function
+               return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLDSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                        const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!publicKey->isOfType(OSSLDSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       HashAlgo::Type hash = HashAlgo::Unknown;
+
+       switch (mechanism)
+       {
+               case AsymMech::DSA_SHA1:
+                       hash = HashAlgo::SHA1;
+                       break;
+               case AsymMech::DSA_SHA224:
+                       hash = HashAlgo::SHA224;
+                       break;
+               case AsymMech::DSA_SHA256:
+                       hash = HashAlgo::SHA256;
+                       break;
+               case AsymMech::DSA_SHA384:
+                       hash = HashAlgo::SHA384;
+                       break;
+               case AsymMech::DSA_SHA512:
+                       hash = HashAlgo::SHA512;
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+       }
+
+       pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash);
+
+
+       if (pCurrentHash == NULL)
+       {
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       if (!pCurrentHash->hashInit())
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLDSA::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       if (!pCurrentHash->hashUpdate(originalData))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLDSA::verifyFinal(const ByteString& signature)
+{
+       // Save necessary state before calling super class verifyFinal
+       OSSLDSAPublicKey* pk = (OSSLDSAPublicKey*) currentPublicKey;
+
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString hash;
+
+       bool bFirstResult = pCurrentHash->hashFinal(hash);
+
+       delete pCurrentHash;
+       pCurrentHash = NULL;
+
+       if (!bFirstResult)
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+       unsigned int sigLen = pk->getOutputLength();
+       if (signature.size() != sigLen)
+               return false;
+       DSA_SIG* sig = DSA_SIG_new();
+       if (sig == NULL)
+               return false;
+       const unsigned char *s = signature.const_byte_str();
+       BIGNUM* bn_r = BN_bin2bn(s, sigLen / 2, NULL);
+       BIGNUM* bn_s = BN_bin2bn(s + sigLen / 2, sigLen / 2, NULL);
+       if (bn_r == NULL || bn_s == NULL ||
+           !DSA_SIG_set0(sig, bn_r, bn_s))
+       {
+               DSA_SIG_free(sig);
+               return false;
+       }
+       int ret = DSA_do_verify(&hash[0], hash.size(), sig, pk->getOSSLKey());
+       if (ret != 1)
+       {
+               if (ret < 0)
+                       ERROR_MSG("DSA verify failed (0x%08X)", ERR_get_error());
+
+               DSA_SIG_free(sig);
+               return false;
+       }
+
+       DSA_SIG_free(sig);
+       return true;
+}
+
+// Encryption functions
+bool OSSLDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                     ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DSA does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool OSSLDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                     ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("DSA does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool OSSLDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(DSAParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for DSA key generation");
+
+               return false;
+       }
+
+       DSAParameters* params = (DSAParameters*) parameters;
+
+       // Generate the key-pair
+       DSA* dsa = DSA_new();
+       if (dsa == NULL)
+       {
+               ERROR_MSG("Failed to instantiate OpenSSL DSA object");
+
+               return false;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+       DSA_set_method(dsa, DSA_get_default_method());
+
+       BIGNUM* bn_p = OSSL::byteString2bn(params->getP());
+       BIGNUM* bn_q = OSSL::byteString2bn(params->getQ());
+       BIGNUM* bn_g = OSSL::byteString2bn(params->getG());
+       DSA_set0_pqg(dsa, bn_p, bn_q, bn_g);
+
+       if (DSA_generate_key(dsa) != 1)
+       {
+               ERROR_MSG("DSA key generation failed (0x%08X)", ERR_get_error());
+
+               DSA_free(dsa);
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       OSSLDSAKeyPair* kp = new OSSLDSAKeyPair();
+
+       ((OSSLDSAPublicKey*) kp->getPublicKey())->setFromOSSL(dsa);
+       ((OSSLDSAPrivateKey*) kp->getPrivateKey())->setFromOSSL(dsa);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       DSA_free(dsa);
+
+       return true;
+}
+
+unsigned long OSSLDSA::getMinKeySize()
+{
+#ifdef WITH_FIPS
+       // OPENSSL_DSA_FIPS_MIN_MODULUS_BITS is 1024
+       return 1024;
+#else
+       return 512;
+#endif
+}
+
+unsigned long OSSLDSA::getMaxKeySize()
+{
+       return OPENSSL_DSA_MAX_MODULUS_BITS;
+}
+
+bool OSSLDSA::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
+{
+       if ((ppParams == NULL) || (parameters == NULL))
+       {
+               return false;
+       }
+
+       size_t bitLen = (size_t) parameters;
+
+       if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
+       {
+               ERROR_MSG("This DSA key size is not supported");
+
+               return false;
+       }
+
+       DSA* dsa = DSA_new();
+
+       if (dsa == NULL ||
+           !DSA_generate_parameters_ex(dsa, bitLen, NULL, 0, NULL, NULL, NULL))
+       {
+               ERROR_MSG("Failed to generate %d bit DSA parameters", bitLen);
+
+               return false;
+       }
+
+       // Store the DSA parameters
+       DSAParameters* params = new DSAParameters();
+
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_g = NULL;
+       DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g);
+
+       ByteString p = OSSL::bn2ByteString(bn_p); params->setP(p);
+       ByteString q = OSSL::bn2ByteString(bn_q); params->setQ(q);
+       ByteString g = OSSL::bn2ByteString(bn_g); params->setG(g);
+
+       *ppParams = params;
+
+       DSA_free(dsa);
+
+       return true;
+}
+
+bool OSSLDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLDSAKeyPair* kp = new OSSLDSAKeyPair();
+
+       bool rv = true;
+
+       if (!((DSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((DSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLDSAPublicKey* pub = new OSSLDSAPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLDSAPrivateKey* priv = new OSSLDSAPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLDSA::newPublicKey()
+{
+       return (PublicKey*) new OSSLDSAPublicKey();
+}
+
+PrivateKey* OSSLDSA::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLDSAPrivateKey();
+}
+
+AsymmetricParameters* OSSLDSA::newParameters()
+{
+       return (AsymmetricParameters*) new DSAParameters();
+}
+
+bool OSSLDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       DSAParameters* params = new DSAParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSA.h b/SoftHSMv2/src/lib/crypto/OSSLDSA.h
new file mode 100644 (file)
index 0000000..1fb2b1e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSA.h
+
+ OpenSSL DSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDSA_H
+#define _SOFTHSM_V2_OSSLDSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include <openssl/dsa.h>
+
+class OSSLDSA : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       OSSLDSA();
+
+       // Destructor
+       virtual ~OSSLDSA();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool generateParameters(AsymmetricParameters** ppParams, void* parameters = NULL, RNG* rng = NULL);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       HashAlgorithm* pCurrentHash;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSA_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp b/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp
new file mode 100644 (file)
index 0000000..aba56f1
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAKeyPair.cpp
+
+ OpenSSL DSA key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDSAKeyPair.h"
+
+// Set the public key
+void OSSLDSAKeyPair::setPublicKey(OSSLDSAPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void OSSLDSAKeyPair::setPrivateKey(OSSLDSAPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* OSSLDSAKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* OSSLDSAKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* OSSLDSAKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* OSSLDSAKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h b/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h
new file mode 100644 (file)
index 0000000..6a0bdf2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAKeyPair.h
+
+ OpenSSL DSA key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDSAKEYPAIR_H
+#define _SOFTHSM_V2_OSSLDSAKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "OSSLDSAPublicKey.h"
+#include "OSSLDSAPrivateKey.h"
+
+class OSSLDSAKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(OSSLDSAPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(OSSLDSAPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       OSSLDSAPublicKey pubKey;
+
+       // The private key
+       OSSLDSAPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSAKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..527e041
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAPrivateKey.cpp
+
+ OpenSSL DSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLComp.h"
+#include "OSSLDSAPrivateKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Constructors
+OSSLDSAPrivateKey::OSSLDSAPrivateKey()
+{
+       dsa = NULL;
+}
+
+OSSLDSAPrivateKey::OSSLDSAPrivateKey(const DSA* inDSA)
+{
+       dsa = NULL;
+
+       setFromOSSL(inDSA);
+}
+
+// Destructor
+OSSLDSAPrivateKey::~OSSLDSAPrivateKey()
+{
+       DSA_free(dsa);
+}
+
+// The type
+/*static*/ const char* OSSLDSAPrivateKey::type = "OpenSSL DSA Private Key";
+
+// Set from OpenSSL representation
+void OSSLDSAPrivateKey::setFromOSSL(const DSA* inDSA)
+{
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_g = NULL;
+       const BIGNUM* bn_priv_key = NULL;
+
+       DSA_get0_pqg(inDSA, &bn_p, &bn_q, &bn_g);
+       DSA_get0_key(inDSA, NULL, &bn_priv_key);
+
+       if (bn_p)
+       {
+               ByteString inP = OSSL::bn2ByteString(bn_p);
+               setP(inP);
+       }
+       if (bn_q)
+       {
+               ByteString inQ = OSSL::bn2ByteString(bn_q);
+               setQ(inQ);
+       }
+       if (bn_g)
+       {
+               ByteString inG = OSSL::bn2ByteString(bn_g);
+               setG(inG);
+       }
+       if (bn_priv_key)
+       {
+               ByteString inX = OSSL::bn2ByteString(bn_priv_key);
+               setX(inX);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLDSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DSA private key components
+void OSSLDSAPrivateKey::setX(const ByteString& inX)
+{
+       DSAPrivateKey::setX(inX);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+
+// Setters for the DSA domain parameters
+void OSSLDSAPrivateKey::setP(const ByteString& inP)
+{
+       DSAPrivateKey::setP(inP);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+void OSSLDSAPrivateKey::setQ(const ByteString& inQ)
+{
+       DSAPrivateKey::setQ(inQ);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+void OSSLDSAPrivateKey::setG(const ByteString& inG)
+{
+       DSAPrivateKey::setG(inG);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString OSSLDSAPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       if (dsa == NULL) createOSSLKey();
+       if (dsa == NULL) return der;
+       EVP_PKEY* pkey = EVP_PKEY_new();
+       if (pkey == NULL) return der;
+       if (!EVP_PKEY_set1_DSA(pkey, dsa))
+       {
+               EVP_PKEY_free(pkey);
+               return der;
+       }
+       PKCS8_PRIV_KEY_INFO* p8inf = EVP_PKEY2PKCS8(pkey);
+       EVP_PKEY_free(pkey);
+       if (p8inf == NULL) return der;
+       int len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, NULL);
+       if (len < 0)
+       {
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return der;
+       }
+       der.resize(len);
+       unsigned char* priv = &der[0];
+       int len2 = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &priv);
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       if (len2 != len) der.wipe();
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool OSSLDSAPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       int len = ber.size();
+       if (len <= 0) return false;
+       const unsigned char* priv = ber.const_byte_str();
+       PKCS8_PRIV_KEY_INFO* p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &priv, len);
+       if (p8 == NULL) return false;
+       EVP_PKEY* pkey = EVP_PKCS82PKEY(p8);
+       PKCS8_PRIV_KEY_INFO_free(p8);
+       if (pkey == NULL) return false;
+       DSA* key = EVP_PKEY_get1_DSA(pkey);
+       EVP_PKEY_free(pkey);
+       if (key == NULL) return false;
+       setFromOSSL(key);
+       DSA_free(key);
+       return true;
+}
+
+// Retrieve the OpenSSL representation of the key
+DSA* OSSLDSAPrivateKey::getOSSLKey()
+{
+       if (dsa == NULL) createOSSLKey();
+
+       return dsa;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLDSAPrivateKey::createOSSLKey()
+{
+       if (dsa != NULL) return;
+
+       BN_CTX *ctx = BN_CTX_new();
+       if (ctx == NULL)
+       {
+               ERROR_MSG("Could not create BN_CTX");
+               return;
+       }
+
+       dsa = DSA_new();
+       if (dsa == NULL)
+       {
+               ERROR_MSG("Could not create DSA object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               DSA_set_method(dsa, FIPS_dsa_openssl());
+       else
+               DSA_set_method(dsa, DSA_OpenSSL());
+#else
+       DSA_set_method(dsa, DSA_OpenSSL());
+#endif
+
+#else
+       DSA_set_method(dsa, DSA_OpenSSL());
+#endif
+
+       BIGNUM* bn_p = OSSL::byteString2bn(p);
+       BIGNUM* bn_q = OSSL::byteString2bn(q);
+       BIGNUM* bn_g = OSSL::byteString2bn(g);
+       BIGNUM* bn_priv_key = OSSL::byteString2bn(x);
+       BIGNUM* bn_pub_key = BN_new();
+
+       BN_mod_exp(bn_pub_key, bn_g, bn_priv_key, bn_p, ctx);
+       BN_CTX_free(ctx);
+
+       DSA_set0_pqg(dsa, bn_p, bn_q, bn_g);
+       DSA_set0_key(dsa, bn_pub_key, bn_priv_key);
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h
new file mode 100644 (file)
index 0000000..0e7a9ef
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAPrivateKey.h
+
+ OpenSSL DSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDSAPRIVATEKEY_H
+#define _SOFTHSM_V2_OSSLDSAPRIVATEKEY_H
+
+#include "config.h"
+#include "DSAPrivateKey.h"
+#include <openssl/dsa.h>
+
+class OSSLDSAPrivateKey : public DSAPrivateKey
+{
+public:
+       // Constructors
+       OSSLDSAPrivateKey();
+
+       OSSLDSAPrivateKey(const DSA* inDSA);
+
+       // Destructor
+       virtual ~OSSLDSAPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DSA private key components
+       virtual void setX(const ByteString& inX);
+
+       // Setters for the DSA domain parameters
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const DSA* inDSA);
+
+       // Retrieve the OpenSSL representation of the key
+       DSA* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       DSA* dsa;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..38ecc79
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAPublicKey.cpp
+
+ OpenSSL DSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDSAPublicKey.h"
+#include "OSSLComp.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Constructors
+OSSLDSAPublicKey::OSSLDSAPublicKey()
+{
+       dsa = NULL;
+}
+
+OSSLDSAPublicKey::OSSLDSAPublicKey(const DSA* inDSA)
+{
+       dsa = NULL;
+
+       setFromOSSL(inDSA);
+}
+
+// Destructor
+OSSLDSAPublicKey::~OSSLDSAPublicKey()
+{
+       DSA_free(dsa);
+}
+
+// The type
+/*static*/ const char* OSSLDSAPublicKey::type = "OpenSSL DSA Public Key";
+
+// Set from OpenSSL representation
+void OSSLDSAPublicKey::setFromOSSL(const DSA* inDSA)
+{
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_g = NULL;
+       const BIGNUM* bn_pub_key = NULL;
+
+       DSA_get0_pqg(inDSA, &bn_p, &bn_q, &bn_g);
+       DSA_get0_key(inDSA, &bn_pub_key, NULL);
+
+       if (bn_p)
+       {
+               ByteString inP = OSSL::bn2ByteString(bn_p);
+               setP(inP);
+       }
+       if (bn_q)
+       {
+               ByteString inQ = OSSL::bn2ByteString(bn_q);
+               setQ(inQ);
+       }
+       if (bn_g)
+       {
+               ByteString inG = OSSL::bn2ByteString(bn_g);
+               setG(inG);
+       }
+       if (bn_pub_key)
+       {
+               ByteString inY = OSSL::bn2ByteString(bn_pub_key);
+               setY(inY);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLDSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the DSA public key components
+void OSSLDSAPublicKey::setP(const ByteString& inP)
+{
+       DSAPublicKey::setP(inP);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+void OSSLDSAPublicKey::setQ(const ByteString& inQ)
+{
+       DSAPublicKey::setQ(inQ);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+void OSSLDSAPublicKey::setG(const ByteString& inG)
+{
+       DSAPublicKey::setG(inG);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+void OSSLDSAPublicKey::setY(const ByteString& inY)
+{
+       DSAPublicKey::setY(inY);
+
+       if (dsa)
+       {
+               DSA_free(dsa);
+               dsa = NULL;
+       }
+}
+
+// Retrieve the OpenSSL representation of the key
+DSA* OSSLDSAPublicKey::getOSSLKey()
+{
+       if (dsa == NULL) createOSSLKey();
+
+       return dsa;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLDSAPublicKey::createOSSLKey()
+{
+       if (dsa != NULL) return;
+
+       dsa = DSA_new();
+       if (dsa == NULL)
+       {
+               ERROR_MSG("Could not create DSA object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               DSA_set_method(dsa, FIPS_dsa_openssl());
+       else
+               DSA_set_method(dsa, DSA_OpenSSL());
+#else
+       DSA_set_method(dsa, DSA_OpenSSL());
+#endif
+
+#else
+       DSA_set_method(dsa, DSA_OpenSSL());
+#endif
+
+       BIGNUM* bn_p = OSSL::byteString2bn(p);
+       BIGNUM* bn_q = OSSL::byteString2bn(q);
+       BIGNUM* bn_g = OSSL::byteString2bn(g);
+       BIGNUM* bn_pub_key = OSSL::byteString2bn(y);
+
+       DSA_set0_pqg(dsa, bn_p, bn_q, bn_g);
+       DSA_set0_key(dsa, bn_pub_key, NULL);
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h b/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h
new file mode 100644 (file)
index 0000000..b30d05c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSAPublicKey.h
+
+ OpenSSL DSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLDSAPUBLICKEY_H
+#define _SOFTHSM_V2_OSSLDSAPUBLICKEY_H
+
+#include "config.h"
+#include "DSAPublicKey.h"
+#include <openssl/dsa.h>
+
+class OSSLDSAPublicKey : public DSAPublicKey
+{
+public:
+       // Constructors
+       OSSLDSAPublicKey();
+
+       OSSLDSAPublicKey(const DSA* inDSA);
+
+       // Destructor
+       virtual ~OSSLDSAPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the DSA public key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setG(const ByteString& inG);
+       virtual void setY(const ByteString& inY);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const DSA* inDSA);
+
+       // Retrieve the OpenSSL representation of the key
+       DSA* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       DSA* dsa;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECDH.cpp b/SoftHSMv2/src/lib/crypto/OSSLECDH.cpp
new file mode 100644 (file)
index 0000000..e2abaeb
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECDH.cpp
+
+ OpenSSL Diffie-Hellman asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECDH.h"
+#include "CryptoFactory.h"
+#include "ECParameters.h"
+#include "OSSLECKeyPair.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/ecdh.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+
+// Signing functions
+bool OSSLECDH::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                       const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+bool OSSLECDH::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+bool OSSLECDH::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDH does not support signing");
+
+       return false;
+}
+
+// Verification functions
+bool OSSLECDH::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                         const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+bool OSSLECDH::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+bool OSSLECDH::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDH does not support verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool OSSLECDH::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                      ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDH does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool OSSLECDH::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                      ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDH does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool OSSLECDH::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for ECDH key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+
+       // Generate the key-pair
+       EC_KEY* eckey = EC_KEY_new();
+
+       if (eckey == NULL)
+       {
+               ERROR_MSG("Failed to instantiate OpenSSL ECDH object");
+
+               return false;
+       }
+
+       EC_GROUP* grp = OSSL::byteString2grp(params->getEC());
+       EC_KEY_set_group(eckey, grp);
+       EC_GROUP_free(grp);
+
+       if (!EC_KEY_generate_key(eckey))
+       {
+               ERROR_MSG("ECDH key generation failed (0x%08X)", ERR_get_error());
+
+               EC_KEY_free(eckey);
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+       ((OSSLECPublicKey*) kp->getPublicKey())->setFromOSSL(eckey);
+       ((OSSLECPrivateKey*) kp->getPrivateKey())->setFromOSSL(eckey);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       EC_KEY_free(eckey);
+
+       return true;
+}
+
+bool OSSLECDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
+{
+       // Check parameters
+       if ((ppSymmetricKey == NULL) ||
+           (publicKey == NULL) ||
+           (privateKey == NULL))
+       {
+               return false;
+       }
+
+       // Get keys
+       EC_KEY *pub = ((OSSLECPublicKey *)publicKey)->getOSSLKey();
+       EC_KEY *priv = ((OSSLECPrivateKey *)privateKey)->getOSSLKey();
+       if (pub == NULL || EC_KEY_get0_public_key(pub) == NULL || priv == NULL)
+       {
+               ERROR_MSG("Failed to get OpenSSL ECDH keys");
+
+               return false;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+       {
+               ECDH_set_method(pub, FIPS_ecdh_openssl());
+               ECDH_set_method(priv, FIPS_ecdh_openssl());
+       }
+       else
+       {
+               ECDH_set_method(pub, ECDH_OpenSSL());
+               ECDH_set_method(priv, ECDH_OpenSSL());
+       }
+#else
+       ECDH_set_method(pub, ECDH_OpenSSL());
+       ECDH_set_method(priv, ECDH_OpenSSL());
+#endif
+
+#else
+       EC_KEY_set_method(pub, EC_KEY_OpenSSL());
+       EC_KEY_set_method(priv, EC_KEY_OpenSSL());
+#endif
+
+       // Derive the secret
+       ByteString secret, derivedSecret;
+       int size = ((OSSLECPublicKey *)publicKey)->getOrderLength();
+       secret.wipe(size);
+       derivedSecret.wipe(size);
+       int keySize = ECDH_compute_key(&derivedSecret[0], derivedSecret.size(), EC_KEY_get0_public_key(pub), priv, NULL);
+
+       if (keySize <= 0)
+       {
+               ERROR_MSG("ECDH key derivation failed (0x%08X)", ERR_get_error());
+
+               return false;
+       }
+
+       // We compensate that OpenSSL removes leading zeros
+       memcpy(&secret[0] + size - keySize, &derivedSecret[0], keySize);
+
+       *ppSymmetricKey = new SymmetricKey(secret.size() * 8);
+       if (*ppSymmetricKey == NULL)
+               return false;
+       if (!(*ppSymmetricKey)->setKeyBits(secret))
+       {
+               delete *ppSymmetricKey;
+               *ppSymmetricKey = NULL;
+               return false;
+       }
+
+       return true;
+}
+
+unsigned long OSSLECDH::getMinKeySize()
+{
+       // Smallest EC group is secp112r1
+       return 112;
+}
+
+unsigned long OSSLECDH::getMaxKeySize()
+{
+       // Biggest EC group is secp521r1
+       return 521;
+}
+
+bool OSSLECDH::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+       bool rv = true;
+
+       if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLECDH::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLECPublicKey* pub = new OSSLECPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLECDH::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLECPrivateKey* priv = new OSSLECPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLECDH::newPublicKey()
+{
+       return (PublicKey*) new OSSLECPublicKey();
+}
+
+PrivateKey* OSSLECDH::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLECPrivateKey();
+}
+
+AsymmetricParameters* OSSLECDH::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool OSSLECDH::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECDH.h b/SoftHSMv2/src/lib/crypto/OSSLECDH.h
new file mode 100644 (file)
index 0000000..2cafa6f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECDH.h
+
+ OpenSSL ECDH asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLECDH_H
+#define _SOFTHSM_V2_OSSLECDH_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <openssl/ecdh.h>
+
+class OSSLECDH : public AsymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~OSSLECDH() { }
+
+       // Signing functions
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey);
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_OSSLECDH_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp b/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp
new file mode 100644 (file)
index 0000000..7387367
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECDSA.cpp
+
+ OpenSSL ECDSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECDSA.h"
+#include "CryptoFactory.h"
+#include "ECParameters.h"
+#include "OSSLECKeyPair.h"
+#include "OSSLComp.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/ecdsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Signing functions
+bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                    ByteString& signature, const AsymMech::Type mechanism,
+                    const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       if (mechanism != AsymMech::ECDSA)
+       {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(OSSLECPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       OSSLECPrivateKey* pk = (OSSLECPrivateKey*) privateKey;
+       EC_KEY* eckey = pk->getOSSLKey();
+
+       if (eckey == NULL)
+       {
+               ERROR_MSG("Could not get the OpenSSL private key");
+
+               return false;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               ECDSA_set_method(eckey, FIPS_ecdsa_openssl());
+       else
+               ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#else
+       ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#endif
+
+#else
+       EC_KEY_set_method(eckey, EC_KEY_OpenSSL());
+#endif
+
+       // Perform the signature operation
+       size_t len = pk->getOrderLength();
+       if (len == 0)
+       {
+               ERROR_MSG("Could not get the order length");
+               return false;
+       }
+       signature.resize(2 * len);
+       memset(&signature[0], 0, 2 * len);
+       ECDSA_SIG *sig = ECDSA_do_sign(dataToSign.const_byte_str(), dataToSign.size(), eckey);
+       if (sig == NULL)
+       {
+               ERROR_MSG("ECDSA sign failed (0x%08X)", ERR_get_error());
+               return false;
+       }
+       // Store the 2 values with padding
+       const BIGNUM* bn_r = NULL;
+       const BIGNUM* bn_s = NULL;
+       ECDSA_SIG_get0(sig, &bn_r, &bn_s);
+       BN_bn2bin(bn_r, &signature[len - BN_num_bytes(bn_r)]);
+       BN_bn2bin(bn_s, &signature[2 * len - BN_num_bytes(bn_s)]);
+       ECDSA_SIG_free(sig);
+       return true;
+}
+
+bool OSSLECDSA::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+                        const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+bool OSSLECDSA::signUpdate(const ByteString& /*dataToSign*/)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+bool OSSLECDSA::signFinal(ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDSA does not support multi part signing");
+
+       return false;
+}
+
+// Verification functions
+bool OSSLECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                      const ByteString& signature, const AsymMech::Type mechanism,
+                      const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       if (mechanism != AsymMech::ECDSA)
+       {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!publicKey->isOfType(OSSLECPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       OSSLECPublicKey* pk = (OSSLECPublicKey*) publicKey;
+       EC_KEY* eckey = pk->getOSSLKey();
+
+       if (eckey == NULL)
+       {
+               ERROR_MSG("Could not get the OpenSSL public key");
+
+               return false;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               ECDSA_set_method(eckey, FIPS_ecdsa_openssl());
+       else
+               ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#else
+       ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#endif
+
+#else
+       EC_KEY_set_method(eckey, EC_KEY_OpenSSL());
+#endif
+
+       // Perform the verify operation
+       size_t len = pk->getOrderLength();
+       if (len == 0)
+       {
+               ERROR_MSG("Could not get the order length");
+               return false;
+       }
+       if (signature.size() != 2 * len)
+       {
+               ERROR_MSG("Invalid buffer length");
+               return false;
+       }
+       ECDSA_SIG* sig = ECDSA_SIG_new();
+       if (sig == NULL)
+       {
+               ERROR_MSG("Could not create an ECDSA_SIG object");
+               return false;
+       }
+       const unsigned char *s = signature.const_byte_str();
+       BIGNUM* bn_r = BN_bin2bn(s, len, NULL);
+       BIGNUM* bn_s = BN_bin2bn(s + len, len, NULL);
+       if (bn_r == NULL || bn_s == NULL ||
+           !ECDSA_SIG_set0(sig, bn_r, bn_s))
+       {
+               ERROR_MSG("Could not add data to the ECDSA_SIG object");
+               ECDSA_SIG_free(sig);
+               return false;
+       }
+       int ret = ECDSA_do_verify(originalData.const_byte_str(), originalData.size(), sig, eckey);
+       if (ret != 1)
+       {
+               if (ret < 0)
+                       ERROR_MSG("ECDSA verify failed (0x%08X)", ERR_get_error());
+
+               ECDSA_SIG_free(sig);
+               return false;
+       }
+
+       ECDSA_SIG_free(sig);
+       return true;
+}
+
+bool OSSLECDSA::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+                          const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+bool OSSLECDSA::verifyUpdate(const ByteString& /*originalData*/)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+bool OSSLECDSA::verifyFinal(const ByteString& /*signature*/)
+{
+       ERROR_MSG("ECDSA does not support multi part verifying");
+
+       return false;
+}
+
+// Encryption functions
+bool OSSLECDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                       ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDSA does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool OSSLECDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                       ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("ECDSA does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool OSSLECDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for ECDSA key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+
+       // Generate the key-pair
+       EC_KEY* eckey = EC_KEY_new();
+       if (eckey == NULL)
+       {
+               ERROR_MSG("Failed to instantiate OpenSSL ECDSA object");
+
+               return false;
+       }
+
+       EC_GROUP* grp = OSSL::byteString2grp(params->getEC());
+       EC_KEY_set_group(eckey, grp);
+       EC_GROUP_free(grp);
+
+       if (!EC_KEY_generate_key(eckey))
+       {
+               ERROR_MSG("ECDSA key generation failed (0x%08X)", ERR_get_error());
+
+               EC_KEY_free(eckey);
+
+               return false;
+       }
+
+       // Create an asymmetric key-pair object to return
+       OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+       ((OSSLECPublicKey*) kp->getPublicKey())->setFromOSSL(eckey);
+       ((OSSLECPrivateKey*) kp->getPrivateKey())->setFromOSSL(eckey);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       EC_KEY_free(eckey);
+
+       return true;
+}
+
+unsigned long OSSLECDSA::getMinKeySize()
+{
+       // Smallest EC group is secp112r1
+       return 112;
+}
+
+unsigned long OSSLECDSA::getMaxKeySize()
+{
+       // Biggest EC group is secp521r1
+       return 521;
+}
+
+bool OSSLECDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+       bool rv = true;
+
+       if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLECDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLECPublicKey* pub = new OSSLECPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLECDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLECPrivateKey* priv = new OSSLECPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLECDSA::newPublicKey()
+{
+       return (PublicKey*) new OSSLECPublicKey();
+}
+
+PrivateKey* OSSLECDSA::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLECPrivateKey();
+}
+
+AsymmetricParameters* OSSLECDSA::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool OSSLECDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECDSA.h b/SoftHSMv2/src/lib/crypto/OSSLECDSA.h
new file mode 100644 (file)
index 0000000..992fa40
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECDSA.h
+
+ OpenSSL ECDSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLECDSA_H
+#define _SOFTHSM_V2_OSSLECDSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <openssl/ecdsa.h>
+
+class OSSLECDSA : public AsymmetricAlgorithm
+{
+public:
+       // Destructor
+       virtual ~OSSLECDSA() { }
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_OSSLECDSA_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp b/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp
new file mode 100644 (file)
index 0000000..2e55f8f
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ OSSLECKeyPair.cpp
+
+ OpenSSL Elliptic Curve key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECKeyPair.h"
+
+// Set the public key
+void OSSLECKeyPair::setPublicKey(OSSLECPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void OSSLECKeyPair::setPrivateKey(OSSLECPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* OSSLECKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* OSSLECKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* OSSLECKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* OSSLECKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h b/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h
new file mode 100644 (file)
index 0000000..ada9b8d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECKeyPair.h
+
+ OpenSSL Elliptic Curve key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLECKEYPAIR_H
+#define _SOFTHSM_V2_OSSLECKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "OSSLECPublicKey.h"
+#include "OSSLECPrivateKey.h"
+
+class OSSLECKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(OSSLECPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(OSSLECPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       OSSLECPublicKey pubKey;
+
+       // The private key
+       OSSLECPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLECKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp
new file mode 100644 (file)
index 0000000..4f6b055
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECPrivateKey.cpp
+
+ OpenSSL EC private key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECPrivateKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+
+// Constructors
+OSSLECPrivateKey::OSSLECPrivateKey()
+{
+       eckey = EC_KEY_new();
+
+       // For PKCS#8 encoding
+       EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+}
+
+OSSLECPrivateKey::OSSLECPrivateKey(const EC_KEY* inECKEY)
+{
+       eckey = EC_KEY_new();
+
+       // For PKCS#8 encoding
+       EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+
+       setFromOSSL(inECKEY);
+}
+
+// Destructor
+OSSLECPrivateKey::~OSSLECPrivateKey()
+{
+       EC_KEY_free(eckey);
+}
+
+// The type
+/*static*/ const char* OSSLECPrivateKey::type = "OpenSSL EC Private Key";
+
+// Get the base point order length
+unsigned long OSSLECPrivateKey::getOrderLength() const
+{
+       const EC_GROUP* grp = EC_KEY_get0_group(eckey);
+       if (grp != NULL)
+       {
+               BIGNUM* order = BN_new();
+               if (order == NULL)
+                       return 0;
+               if (!EC_GROUP_get_order(grp, order, NULL))
+               {
+                       BN_clear_free(order);
+                       return 0;
+               }
+               unsigned long len = BN_num_bytes(order);
+               BN_clear_free(order);
+               return len;
+       }
+       return 0;
+}
+
+// Set from OpenSSL representation
+void OSSLECPrivateKey::setFromOSSL(const EC_KEY* inECKEY)
+{
+       const EC_GROUP* grp = EC_KEY_get0_group(inECKEY);
+       if (grp != NULL)
+       {
+               ByteString inEC = OSSL::grp2ByteString(grp);
+               setEC(inEC);
+       }
+       const BIGNUM* pk = EC_KEY_get0_private_key(inECKEY);
+       if (pk != NULL)
+       {
+               ByteString inD = OSSL::bn2ByteString(pk);
+               setD(inD);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLECPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the EC private key components
+void OSSLECPrivateKey::setD(const ByteString& inD)
+{
+       ECPrivateKey::setD(inD);
+
+       BIGNUM* pk = OSSL::byteString2bn(inD);
+       EC_KEY_set_private_key(eckey, pk);
+       BN_clear_free(pk);
+}
+
+
+// Setters for the EC public key components
+void OSSLECPrivateKey::setEC(const ByteString& inEC)
+{
+       ECPrivateKey::setEC(inEC);
+
+       EC_GROUP* grp = OSSL::byteString2grp(inEC);
+       EC_KEY_set_group(eckey, grp);
+       EC_GROUP_free(grp);
+}
+
+// Encode into PKCS#8 DER
+ByteString OSSLECPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       if (eckey == NULL) return der;
+       EVP_PKEY* pkey = EVP_PKEY_new();
+       if (pkey == NULL) return der;
+       if (!EVP_PKEY_set1_EC_KEY(pkey, eckey))
+       {
+               EVP_PKEY_free(pkey);
+               return der;
+       }
+       PKCS8_PRIV_KEY_INFO* p8inf = EVP_PKEY2PKCS8(pkey);
+       EVP_PKEY_free(pkey);
+       if (p8inf == NULL) return der;
+       int len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, NULL);
+       if (len < 0)
+       {
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return der;
+       }
+       der.resize(len);
+       unsigned char* priv = &der[0];
+       int len2 = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &priv);
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       if (len2 != len) der.wipe();
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool OSSLECPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       int len = ber.size();
+       if (len <= 0) return false;
+       const unsigned char* priv = ber.const_byte_str();
+       PKCS8_PRIV_KEY_INFO* p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &priv, len);
+       if (p8 == NULL) return false;
+       EVP_PKEY* pkey = EVP_PKCS82PKEY(p8);
+       PKCS8_PRIV_KEY_INFO_free(p8);
+       if (pkey == NULL) return false;
+       EC_KEY* key = EVP_PKEY_get1_EC_KEY(pkey);
+       EVP_PKEY_free(pkey);
+       if (key == NULL) return false;
+       setFromOSSL(key);
+       EC_KEY_free(key);
+       return true;
+}
+
+// Retrieve the OpenSSL representation of the key
+EC_KEY* OSSLECPrivateKey::getOSSLKey()
+{
+       return eckey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h b/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h
new file mode 100644 (file)
index 0000000..152ad03
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECPrivateKey.h
+
+ OpenSSL Elliptic Curve private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLECPRIVATEKEY_H
+#define _SOFTHSM_V2_OSSLECPRIVATEKEY_H
+
+#include "config.h"
+#include "ECPrivateKey.h"
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+
+class OSSLECPrivateKey : public ECPrivateKey
+{
+public:
+       // Constructors
+       OSSLECPrivateKey();
+
+       OSSLECPrivateKey(const EC_KEY* inECKEY);
+
+       // Destructor
+       virtual ~OSSLECPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the EC private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the EC public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const EC_KEY* inECKEY);
+
+       // Retrieve the OpenSSL representation of the key
+       EC_KEY* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       EC_KEY* eckey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp
new file mode 100644 (file)
index 0000000..b2d80af
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ OSSLECPublicKey.cpp
+
+ OpenSSL Elliptic Curve public key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECPublicKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#include <string.h>
+
+// Constructors
+OSSLECPublicKey::OSSLECPublicKey()
+{
+       eckey = EC_KEY_new();
+}
+
+OSSLECPublicKey::OSSLECPublicKey(const EC_KEY* inECKEY)
+{
+       eckey = EC_KEY_new();
+
+       setFromOSSL(inECKEY);
+}
+
+// Destructor
+OSSLECPublicKey::~OSSLECPublicKey()
+{
+       EC_KEY_free(eckey);
+}
+
+// The type
+/*static*/ const char* OSSLECPublicKey::type = "OpenSSL EC Public Key";
+
+// Get the base point order length
+unsigned long OSSLECPublicKey::getOrderLength() const
+{
+       const EC_GROUP* grp = EC_KEY_get0_group(eckey);
+       if (grp != NULL)
+       {
+               BIGNUM* order = BN_new();
+               if (order == NULL)
+                       return 0;
+               if (!EC_GROUP_get_order(grp, order, NULL))
+               {
+                       BN_clear_free(order);
+                       return 0;
+               }
+               unsigned long len = BN_num_bytes(order);
+               BN_clear_free(order);
+               return len;
+       }
+       return 0;
+}
+
+// Set from OpenSSL representation
+void OSSLECPublicKey::setFromOSSL(const EC_KEY* inECKEY)
+{
+       const EC_GROUP* grp = EC_KEY_get0_group(inECKEY);
+       if (grp != NULL)
+       {
+               ByteString inEC = OSSL::grp2ByteString(grp);
+               setEC(inEC);
+       }
+       const EC_POINT* pub = EC_KEY_get0_public_key(inECKEY);
+       if (pub != NULL && grp != NULL)
+       {
+               ByteString inQ = OSSL::pt2ByteString(pub, grp);
+               setQ(inQ);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLECPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the EC public key components
+void OSSLECPublicKey::setEC(const ByteString& inEC)
+{
+       ECPublicKey::setEC(inEC);
+
+       EC_GROUP* grp = OSSL::byteString2grp(inEC);
+       EC_KEY_set_group(eckey, grp);
+       EC_GROUP_free(grp);
+}
+
+void OSSLECPublicKey::setQ(const ByteString& inQ)
+{
+       ECPublicKey::setQ(inQ);
+
+       EC_POINT* pub = OSSL::byteString2pt(inQ, EC_KEY_get0_group(eckey));
+       EC_KEY_set_public_key(eckey, pub);
+       EC_POINT_free(pub);
+}
+
+// Retrieve the OpenSSL representation of the key
+EC_KEY* OSSLECPublicKey::getOSSLKey()
+{
+       return eckey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h b/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h
new file mode 100644 (file)
index 0000000..3fb4f35
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLECPublicKey.h
+
+ OpenSSL Elliptic Curve public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLECPUBLICKEY_H
+#define _SOFTHSM_V2_OSSLECPUBLICKEY_H
+
+#include "config.h"
+#include "ECPublicKey.h"
+#include <openssl/ec.h>
+
+class OSSLECPublicKey : public ECPublicKey
+{
+public:
+       // Constructors
+       OSSLECPublicKey();
+
+       OSSLECPublicKey(const EC_KEY* inECKEY);
+
+       // Destructor
+       virtual ~OSSLECPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the base point order length
+       virtual unsigned long getOrderLength() const;
+
+       // Setters for the EC public key components
+       virtual void setEC(const ByteString& inEC);
+       virtual void setQ(const ByteString& inQ);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const EC_KEY* inECKEY);
+
+       // Retrieve the OpenSSL representation of the key
+       EC_KEY* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       EC_KEY* eckey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp
new file mode 100644 (file)
index 0000000..27e29d9
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+// TODO: Store context in securely allocated memory
+
+/*****************************************************************************
+ OSSLEVPCMacAlgorithm.cpp
+
+ OpenSSL CMAC algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLEVPCMacAlgorithm.h"
+#include "OSSLComp.h"
+#include <openssl/err.h>
+
+// Destructor
+OSSLEVPCMacAlgorithm::~OSSLEVPCMacAlgorithm()
+{
+       if (curCTX != NULL)
+               CMAC_CTX_free(curCTX);
+}
+
+// Signing functions
+bool OSSLEVPCMacAlgorithm::signInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::signInit(key))
+       {
+               return false;
+       }
+
+       // Determine the cipher class
+       const EVP_CIPHER* cipher = getEVPCipher();
+       if (cipher == NULL)
+       {
+               ERROR_MSG("Invalid sign mac algorithm");
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       // Initialize the context
+       curCTX = CMAC_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for CMAC_CTX");
+
+               return false;
+       }
+
+       // Initialize EVP signing
+       if (!CMAC_Init(curCTX, key->getKeyBits().const_byte_str(), key->getKeyBits().size(), cipher, NULL))
+       {
+               ERROR_MSG("CMAC_Init failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPCMacAlgorithm::signUpdate(const ByteString& dataToSign)
+{
+       if (!MacAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       if (dataToSign.size() == 0) return true;
+
+       if (!CMAC_Update(curCTX, dataToSign.const_byte_str(), dataToSign.size()))
+       {
+               ERROR_MSG("CMAC_Update failed");
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPCMacAlgorithm::signFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       size_t outLen = getMacSize();
+       signature.resize(outLen);
+
+       if (!CMAC_Final(curCTX, &signature[0], &outLen))
+       {
+               ERROR_MSG("CMAC_Final failed");
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       signature.resize(outLen);
+
+       CMAC_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool OSSLEVPCMacAlgorithm::verifyInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::verifyInit(key))
+       {
+               return false;
+       }
+
+       // Determine the cipher class
+       const EVP_CIPHER* cipher = getEVPCipher();
+       if (cipher == NULL)
+       {
+               ERROR_MSG("Invalid verify mac algorithm");
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       // Initialize the context
+       curCTX = CMAC_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for CMAC_CTX");
+
+               return false;
+       }
+
+       // Initialize EVP signing
+       if (!CMAC_Init(curCTX, key->getKeyBits().const_byte_str(), key->getKeyBits().size(), cipher, NULL))
+       {
+               ERROR_MSG("CMAC_Init failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPCMacAlgorithm::verifyUpdate(const ByteString& originalData)
+{
+       if (!MacAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       if (originalData.size() == 0) return true;
+
+       if (!CMAC_Update(curCTX, originalData.const_byte_str(), originalData.size()))
+       {
+               ERROR_MSG("CMAC_Update failed");
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPCMacAlgorithm::verifyFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString macResult;
+       size_t outLen = getMacSize();
+       macResult.resize(outLen);
+
+       if (!CMAC_Final(curCTX, &macResult[0], &outLen))
+       {
+               ERROR_MSG("CMAC_Final failed");
+
+               CMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       CMAC_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return macResult == signature;
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h b/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h
new file mode 100644 (file)
index 0000000..621e995
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+/*****************************************************************************
+ OSSLEVPCMacAlgorithm.h
+
+ OpenSSL CMAC algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLEVPCMACALGORITHM_H
+#define _SOFTHSM_V2_OSSLEVPCMACALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "MacAlgorithm.h"
+#include <openssl/evp.h>
+#include <openssl/cmac.h>
+
+class OSSLEVPCMacAlgorithm : public MacAlgorithm
+{
+public:
+       // Constructor
+       OSSLEVPCMacAlgorithm() {
+               curCTX = NULL;
+       };
+
+       // Destructor
+       ~OSSLEVPCMacAlgorithm();
+
+       // Signing functions
+       virtual bool signInit(const SymmetricKey* key);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(const SymmetricKey* key);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(ByteString& signature);
+
+       // Return the MAC size
+       virtual size_t getMacSize() const = 0;
+
+protected:
+       // Return the right cipher for the operation
+       virtual const EVP_CIPHER* getEVPCipher() const = 0;
+
+private:
+       // The current context
+       CMAC_CTX* curCTX;
+};
+
+#endif // !_SOFTHSM_V2_OSSLEVPCMACALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp
new file mode 100644 (file)
index 0000000..a1b4f73
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLEVPHashAlgorithm.cpp
+
+ Base class for OpenSSL hash algorithm classes
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include "OSSLComp.h"
+
+// Destructor
+OSSLEVPHashAlgorithm::~OSSLEVPHashAlgorithm()
+{
+       EVP_MD_CTX_free(curCTX);
+}
+
+// Hashing functions
+bool OSSLEVPHashAlgorithm::hashInit()
+{
+       if (!HashAlgorithm::hashInit())
+       {
+               return false;
+       }
+
+       // Initialize the context
+       curCTX = EVP_MD_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_MD_CTX");
+
+               return false;
+       }
+
+       // Initialize EVP digesting
+       if (!EVP_DigestInit_ex(curCTX, getEVPHash(), NULL))
+       {
+               ERROR_MSG("EVP_DigestInit failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               HashAlgorithm::hashFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPHashAlgorithm::hashUpdate(const ByteString& data)
+{
+       if (!HashAlgorithm::hashUpdate(data))
+       {
+               return false;
+       }
+
+       // Continue digesting
+       if (data.size() == 0)
+       {
+               return true;
+       }
+
+       if (!EVP_DigestUpdate(curCTX, (unsigned char*) data.const_byte_str(), data.size()))
+       {
+               ERROR_MSG("EVP_DigestUpdate failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               HashAlgorithm::hashFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPHashAlgorithm::hashFinal(ByteString& hashedData)
+{
+       if (!HashAlgorithm::hashFinal(hashedData))
+       {
+               return false;
+       }
+
+       hashedData.resize(EVP_MD_size(getEVPHash()));
+       unsigned int outLen = hashedData.size();
+
+       if (!EVP_DigestFinal_ex(curCTX, &hashedData[0], &outLen))
+       {
+               ERROR_MSG("EVP_DigestFinal failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       hashedData.resize(outLen);
+
+       EVP_MD_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h b/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h
new file mode 100644 (file)
index 0000000..1775df2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLEVPHashAlgorithm.h
+
+ Base class for OpenSSL hash algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLEVPHASHALGORITHM_H
+#define _SOFTHSM_V2_OSSLEVPHASHALGORITHM_H
+
+#include "config.h"
+#include "HashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLEVPHashAlgorithm : public HashAlgorithm
+{
+public:
+       // Base constructors
+       OSSLEVPHashAlgorithm() : HashAlgorithm() {
+               curCTX = NULL;
+       }
+
+       // Destructor
+       ~OSSLEVPHashAlgorithm();
+
+       // Hashing functions
+       virtual bool hashInit();
+       virtual bool hashUpdate(const ByteString& data);
+       virtual bool hashFinal(ByteString& hashedData);
+
+       virtual int getHashSize() = 0;
+protected:
+       virtual const EVP_MD* getEVPHash() const = 0;
+
+private:
+       // Current hashing context
+       EVP_MD_CTX* curCTX;
+};
+
+#endif // !_SOFTHSM_V2_OSSLEVPHASHALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp
new file mode 100644 (file)
index 0000000..960b341
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+// TODO: Store context in securely allocated memory
+
+/*****************************************************************************
+ OSSLEVPMacAlgorithm.cpp
+
+ OpenSSL MAC algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLEVPMacAlgorithm.h"
+#include "OSSLComp.h"
+
+// Destructor
+OSSLEVPMacAlgorithm::~OSSLEVPMacAlgorithm()
+{
+       HMAC_CTX_free(curCTX);
+}
+
+// Signing functions
+bool OSSLEVPMacAlgorithm::signInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::signInit(key))
+       {
+               return false;
+       }
+
+       // Initialize the context
+       curCTX = HMAC_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for HMAC_CTX");
+
+               return false;
+       }
+
+       // Initialize EVP signing
+       if (!HMAC_Init_ex(curCTX, key->getKeyBits().const_byte_str(), key->getKeyBits().size(), getEVPHash(), NULL))
+       {
+               ERROR_MSG("HMAC_Init failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPMacAlgorithm::signUpdate(const ByteString& dataToSign)
+{
+       if (!MacAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       // The GOST implementation in OpenSSL will segfault if we update with zero length.
+       if (dataToSign.size() == 0) return true;
+
+       if (!HMAC_Update(curCTX, dataToSign.const_byte_str(), dataToSign.size()))
+       {
+               ERROR_MSG("HMAC_Update failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPMacAlgorithm::signFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       signature.resize(EVP_MD_size(getEVPHash()));
+       unsigned int outLen = signature.size();
+
+       if (!HMAC_Final(curCTX, &signature[0], &outLen))
+       {
+               ERROR_MSG("HMAC_Final failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       signature.resize(outLen);
+
+       HMAC_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool OSSLEVPMacAlgorithm::verifyInit(const SymmetricKey* key)
+{
+       // Call the superclass initialiser
+       if (!MacAlgorithm::verifyInit(key))
+       {
+               return false;
+       }
+
+       // Initialize the context
+       curCTX = HMAC_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for HMAC_CTX");
+
+               return false;
+       }
+
+       // Initialize EVP signing
+       if (!HMAC_Init_ex(curCTX, key->getKeyBits().const_byte_str(), key->getKeyBits().size(), getEVPHash(), NULL))
+       {
+               ERROR_MSG("HMAC_Init failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPMacAlgorithm::verifyUpdate(const ByteString& originalData)
+{
+       if (!MacAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       // The GOST implementation in OpenSSL will segfault if we update with zero length.
+       if (originalData.size() == 0) return true;
+
+       if (!HMAC_Update(curCTX, originalData.const_byte_str(), originalData.size()))
+       {
+               ERROR_MSG("HMAC_Update failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               MacAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLEVPMacAlgorithm::verifyFinal(ByteString& signature)
+{
+       if (!MacAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString macResult;
+       unsigned int outLen = EVP_MD_size(getEVPHash());
+       macResult.resize(outLen);
+
+       if (!HMAC_Final(curCTX, &macResult[0], &outLen))
+       {
+               ERROR_MSG("HMAC_Final failed");
+
+               HMAC_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       HMAC_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return macResult == signature;
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h b/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h
new file mode 100644 (file)
index 0000000..69e3f18
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLEVPMacAlgorithm.h
+
+ OpenSSL MAC algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLEVPMACALGORITHM_H
+#define _SOFTHSM_V2_OSSLEVPMACALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "MacAlgorithm.h"
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+class OSSLEVPMacAlgorithm : public MacAlgorithm
+{
+public:
+       // Constructor
+       OSSLEVPMacAlgorithm() {
+               curCTX = NULL;
+       };
+
+       // Destructor
+       ~OSSLEVPMacAlgorithm();
+
+       // Signing functions
+       virtual bool signInit(const SymmetricKey* key);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verifyInit(const SymmetricKey* key);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(ByteString& signature);
+
+       // Return the MAC size
+       virtual size_t getMacSize() const = 0;
+
+protected:
+       // Return the right hash for the operation
+       virtual const EVP_MD* getEVPHash() const = 0;
+
+private:
+       // The current context
+       HMAC_CTX* curCTX;
+};
+
+#endif // !_SOFTHSM_V2_OSSLEVPMACALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp
new file mode 100644 (file)
index 0000000..d43e741
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * 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.
+ */
+
+// TODO: Store EVP context in securely allocated memory
+
+/*****************************************************************************
+ OSSLEVPSymmetricAlgorithm.cpp
+
+ OpenSSL symmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLEVPSymmetricAlgorithm.h"
+#include "OSSLUtil.h"
+#include "salloc.h"
+#include <openssl/err.h>
+
+// Constructor
+OSSLEVPSymmetricAlgorithm::OSSLEVPSymmetricAlgorithm()
+{
+       pCurCTX = NULL;
+       maximumBytes = BN_new();
+       BN_one(maximumBytes);
+       BN_set_negative(maximumBytes, 1);
+       counterBytes = BN_new();
+       BN_zero(counterBytes);
+}
+
+// Destructor
+OSSLEVPSymmetricAlgorithm::~OSSLEVPSymmetricAlgorithm()
+{
+       EVP_CIPHER_CTX_free(pCurCTX);
+       BN_free(maximumBytes);
+       BN_free(counterBytes);
+}
+
+// Encryption functions
+bool OSSLEVPSymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode::CBC */, const ByteString& IV /* = ByteString()*/, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */)
+{
+       // Call the superclass initialiser
+       if (!SymmetricAlgorithm::encryptInit(key, mode, IV, padding, counterBits, aad, tagBytes))
+       {
+               return false;
+       }
+
+       // Check the IV
+       if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
+       {
+               ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       ByteString iv;
+
+       if (IV.size() > 0)
+       {
+               iv = IV;
+       }
+       else
+       {
+               iv.wipe(getBlockSize());
+       }
+
+       // Check the counter bits
+       if (counterBits > 0)
+       {
+               BIGNUM* counter = OSSL::byteString2bn(iv);
+               BN_mask_bits(counter, counterBits);
+
+               // Reverse the bits
+               while (counterBits > 0)
+               {
+                       counterBits--;
+                       if (BN_is_bit_set(counter, counterBits))
+                       {
+                               BN_clear_bit(counter, counterBits);
+                       }
+                       else
+                       {
+                               BN_set_bit(counter, counterBits);
+                       }
+               }
+
+               // Set the maximum bytes
+               BN_add_word(counter, 1);
+               BN_mul_word(counter, getBlockSize());
+               BN_copy(maximumBytes, counter);
+               BN_free(counter);
+               BN_zero(counterBytes);
+       }
+       else
+       {
+               BN_one(maximumBytes);
+               BN_set_negative(maximumBytes, 1);
+       }
+
+       // Determine the cipher class
+       const EVP_CIPHER* cipher = getCipher();
+
+       if (cipher == NULL)
+       {
+               ERROR_MSG("Failed to initialise EVP encrypt operation");
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the EVP context
+       pCurCTX = EVP_CIPHER_CTX_new();
+
+       if (pCurCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_CIPHER_CTX");
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       int rv;
+       if (mode == SymMode::GCM)
+       {
+               rv = EVP_EncryptInit_ex(pCurCTX, cipher, NULL, NULL, NULL);
+
+               if (rv)
+               {
+                       EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_GCM_SET_IVLEN, iv.size(), NULL);
+                       rv = EVP_EncryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str());
+               }
+       }
+       else
+       {
+               rv = EVP_EncryptInit(pCurCTX, cipher, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str());
+       }
+
+       if (!rv)
+       {
+               ERROR_MSG("Failed to initialise EVP encrypt operation: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       EVP_CIPHER_CTX_set_padding(pCurCTX, padding ? 1 : 0);
+
+       if (mode == SymMode::GCM)
+       {
+               int outLen = 0;
+               if (aad.size() && !EVP_EncryptUpdate(pCurCTX, NULL, &outLen, (unsigned char*) aad.const_byte_str(), aad.size()))
+               {
+                       ERROR_MSG("Failed to update with AAD: %s", ERR_error_string(ERR_get_error(), NULL));
+
+                       EVP_CIPHER_CTX_free(pCurCTX);
+                       pCurCTX = NULL;
+
+                       ByteString dummy;
+                       SymmetricAlgorithm::encryptFinal(dummy);
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool OSSLEVPSymmetricAlgorithm::encryptUpdate(const ByteString& data, ByteString& encryptedData)
+{
+       if (!SymmetricAlgorithm::encryptUpdate(data, encryptedData))
+       {
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       if (data.size() == 0)
+       {
+               encryptedData.resize(0);
+
+               return true;
+       }
+
+       // Count number of bytes written
+       if (!BN_is_negative(maximumBytes))
+       {
+               BN_add_word(counterBytes, data.size());
+       }
+
+       // Prepare the output block
+       encryptedData.resize(data.size() + getBlockSize() - 1);
+
+       int outLen = encryptedData.size();
+       if (!EVP_EncryptUpdate(pCurCTX, &encryptedData[0], &outLen, (unsigned char*) data.const_byte_str(), data.size()))
+       {
+               ERROR_MSG("EVP_EncryptUpdate failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               ByteString dummy;
+               SymmetricAlgorithm::encryptFinal(dummy);
+
+               return false;
+       }
+
+       // Resize the output block
+       encryptedData.resize(outLen);
+       currentBufferSize -= outLen;
+
+       return true;
+}
+
+bool OSSLEVPSymmetricAlgorithm::encryptFinal(ByteString& encryptedData)
+{
+       SymMode::Type mode = currentCipherMode;
+       size_t tagBytes = currentTagBytes;
+
+       if (!SymmetricAlgorithm::encryptFinal(encryptedData))
+       {
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       // Prepare the output block
+       encryptedData.resize(getBlockSize());
+
+       int outLen = encryptedData.size();
+
+       if (!EVP_EncryptFinal(pCurCTX, &encryptedData[0], &outLen))
+       {
+               ERROR_MSG("EVP_EncryptFinal failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       // Resize the output block
+       encryptedData.resize(outLen);
+
+       if (mode == SymMode::GCM)
+       {
+               ByteString tag;
+               tag.resize(tagBytes);
+               EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_GCM_GET_TAG, tagBytes, &tag[0]);
+               encryptedData += tag;
+       }
+
+       EVP_CIPHER_CTX_free(pCurCTX);
+       pCurCTX = NULL;
+
+       return true;
+}
+
+// Decryption functions
+bool OSSLEVPSymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode::CBC */, const ByteString& IV /* = ByteString() */, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& aad /* = ByteString() */, size_t tagBytes /* = 0 */)
+{
+       // Call the superclass initialiser
+       if (!SymmetricAlgorithm::decryptInit(key, mode, IV, padding, counterBits, aad, tagBytes))
+       {
+               return false;
+       }
+
+       // Check the IV
+       if (mode != SymMode::GCM && (IV.size() > 0) && (IV.size() != getBlockSize()))
+       {
+               ERROR_MSG("Invalid IV size (%d bytes, expected %d bytes)", IV.size(), getBlockSize());
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       ByteString iv;
+
+       if (IV.size() > 0)
+       {
+               iv = IV;
+       }
+       else
+       {
+               iv.wipe(getBlockSize());
+       }
+
+       // Check the counter bits
+       if (counterBits > 0)
+       {
+               BIGNUM* counter = OSSL::byteString2bn(iv);
+               BN_mask_bits(counter, counterBits);
+
+               // Reverse the bits
+               while (counterBits > 0)
+               {
+                       counterBits--;
+                       if (BN_is_bit_set(counter, counterBits))
+                       {
+                               BN_clear_bit(counter, counterBits);
+                       }
+                       else
+                       {
+                               BN_set_bit(counter, counterBits);
+                       }
+               }
+
+               // Set the maximum bytes
+               BN_add_word(counter, 1);
+               BN_mul_word(counter, getBlockSize());
+               BN_copy(maximumBytes, counter);
+               BN_free(counter);
+               BN_zero(counterBytes);
+       }
+       else
+       {
+               BN_one(maximumBytes);
+               BN_set_negative(maximumBytes, 1);
+       }
+
+       // Determine the cipher class
+       const EVP_CIPHER* cipher = getCipher();
+
+       if (cipher == NULL)
+       {
+               ERROR_MSG("Failed to initialise EVP decrypt operation");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       // Allocate the EVP context
+       pCurCTX = EVP_CIPHER_CTX_new();
+
+       if (pCurCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_CIPHER_CTX");
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       int rv;
+       if (mode == SymMode::GCM)
+       {
+               rv = EVP_DecryptInit_ex(pCurCTX, cipher, NULL, NULL, NULL);
+
+               if (rv)
+               {
+                       EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_GCM_SET_IVLEN, iv.size(), NULL);
+                       rv = EVP_DecryptInit_ex(pCurCTX, NULL, NULL, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str());
+               }
+       }
+       else
+       {
+               rv = EVP_DecryptInit(pCurCTX, cipher, (unsigned char*) currentKey->getKeyBits().const_byte_str(), iv.byte_str());
+       }
+
+       if (!rv)
+       {
+               ERROR_MSG("Failed to initialise EVP decrypt operation: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       EVP_CIPHER_CTX_set_padding(pCurCTX, padding ? 1 : 0);
+
+       if (mode == SymMode::GCM)
+       {
+               int outLen = 0;
+               if (aad.size() && !EVP_DecryptUpdate(pCurCTX, NULL, &outLen, (unsigned char*) aad.const_byte_str(), aad.size()))
+               {
+                       ERROR_MSG("Failed to update with AAD: %s", ERR_error_string(ERR_get_error(), NULL));
+
+                       EVP_CIPHER_CTX_free(pCurCTX);
+                       pCurCTX = NULL;
+
+                       ByteString dummy;
+                       SymmetricAlgorithm::decryptFinal(dummy);
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool OSSLEVPSymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, ByteString& data)
+{
+       if (!SymmetricAlgorithm::decryptUpdate(encryptedData, data))
+       {
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       // AEAD ciphers should not return decrypted data until final is called
+       if (currentCipherMode == SymMode::GCM)
+       {
+               data.resize(0);
+               return true;
+       }
+
+       // Count number of bytes written
+       if (!BN_is_negative(maximumBytes))
+       {
+               BN_add_word(counterBytes, encryptedData.size());
+       }
+
+       // Prepare the output block
+       data.resize(encryptedData.size() + getBlockSize());
+
+       int outLen = data.size();
+
+       DEBUG_MSG("Decrypting %d bytes into buffer of %d bytes", encryptedData.size(), data.size());
+
+       if (!EVP_DecryptUpdate(pCurCTX, &data[0], &outLen, (unsigned char*) encryptedData.const_byte_str(), encryptedData.size()))
+       {
+               ERROR_MSG("EVP_DecryptUpdate failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               ByteString dummy;
+               SymmetricAlgorithm::decryptFinal(dummy);
+
+               return false;
+       }
+
+       DEBUG_MSG("Decrypt returned %d bytes of data", outLen);
+
+       // Resize the output block
+       data.resize(outLen);
+       currentBufferSize -= outLen;
+
+       return true;
+}
+
+bool OSSLEVPSymmetricAlgorithm::decryptFinal(ByteString& data)
+{
+       SymMode::Type mode = currentCipherMode;
+       size_t tagBytes = currentTagBytes;
+       ByteString aeadBuffer = currentAEADBuffer;
+
+       if (!SymmetricAlgorithm::decryptFinal(data))
+       {
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       data.resize(0);
+       if (mode == SymMode::GCM)
+       {
+               // Check buffer size
+               if (aeadBuffer.size() < tagBytes)
+               {
+                       ERROR_MSG("Tag bytes (%d) does not fit in AEAD buffer (%d)", tagBytes, aeadBuffer.size());
+
+                       EVP_CIPHER_CTX_free(pCurCTX);
+                       pCurCTX = NULL;
+
+                       return false;
+               }
+
+               // Set the tag
+               EVP_CIPHER_CTX_ctrl(pCurCTX, EVP_CTRL_GCM_SET_TAG, tagBytes, &aeadBuffer[aeadBuffer.size()-tagBytes]);
+
+               // Prepare the output block
+               data.resize(aeadBuffer.size() - tagBytes + getBlockSize());
+               int outLen = data.size();
+
+               if (!EVP_DecryptUpdate(pCurCTX, &data[0], &outLen, (unsigned char*) aeadBuffer.const_byte_str(), aeadBuffer.size() - tagBytes))
+               {
+                       ERROR_MSG("EVP_DecryptUpdate failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+                       EVP_CIPHER_CTX_free(pCurCTX);
+                       pCurCTX = NULL;
+
+                       return false;
+               }
+
+               data.resize(outLen);
+       }
+
+       // Prepare the output block
+       int initialSize = data.size();
+       data.resize(initialSize + getBlockSize());
+
+       int outLen = data.size() - initialSize;
+       int rv;
+
+       if (!(rv = EVP_DecryptFinal(pCurCTX, &data[initialSize], &outLen)))
+       {
+               ERROR_MSG("EVP_DecryptFinal failed (0x%08X): %s", rv, ERR_error_string(ERR_get_error(), NULL));
+
+               EVP_CIPHER_CTX_free(pCurCTX);
+               pCurCTX = NULL;
+
+               return false;
+       }
+
+       // Resize the output block
+       data.resize(initialSize + outLen);
+
+       EVP_CIPHER_CTX_free(pCurCTX);
+       pCurCTX = NULL;
+
+       return true;
+}
+
+// Check if more bytes of data can be encrypted
+bool OSSLEVPSymmetricAlgorithm::checkMaximumBytes(unsigned long bytes)
+{
+       if (BN_is_negative(maximumBytes)) return true;
+
+       BIGNUM* bigNum = BN_new();
+       BN_copy(bigNum, counterBytes);
+       BN_add_word(bigNum, bytes);
+
+       bool rv = false;
+       if (BN_cmp(maximumBytes, bigNum) >= 0) rv = true;
+
+       BN_free(bigNum);
+
+       return rv;
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.h b/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.h
new file mode 100644 (file)
index 0000000..66bbeef
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLEVPSymmetricAlgorithm.h
+
+ OpenSSL symmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLEVPSYMMETRICALGORITHM_H
+#define _SOFTHSM_V2_OSSLEVPSYMMETRICALGORITHM_H
+
+#include <openssl/evp.h>
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "SymmetricAlgorithm.h"
+
+class OSSLEVPSymmetricAlgorithm : public SymmetricAlgorithm
+{
+public:
+       // Constructor
+       OSSLEVPSymmetricAlgorithm();
+
+       // Destructor
+       virtual ~OSSLEVPSymmetricAlgorithm();
+
+       // Encryption functions
+       virtual bool encryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool encryptUpdate(const ByteString& data, ByteString& encryptedData);
+       virtual bool encryptFinal(ByteString& encryptedData);
+
+       // Decryption functions
+       virtual bool decryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool decryptUpdate(const ByteString& encryptedData, ByteString& data);
+       virtual bool decryptFinal(ByteString& data);
+
+       // Return the block size
+       virtual size_t getBlockSize() const = 0;
+
+       // Check if more bytes of data can be encrypted
+       virtual bool checkMaximumBytes(unsigned long bytes);
+
+protected:
+       // Return the right EVP cipher for the operation
+       virtual const EVP_CIPHER* getCipher() const = 0;
+
+private:
+       // The current EVP context
+       EVP_CIPHER_CTX* pCurCTX;
+
+       // The maximum bytes to encrypt/decrypt
+       BIGNUM* maximumBytes;
+       BIGNUM* counterBytes;
+};
+
+#endif // !_SOFTHSM_V2_OSSLEVPSYMMETRICALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOST.cpp b/SoftHSMv2/src/lib/crypto/OSSLGOST.cpp
new file mode 100644 (file)
index 0000000..4f34d45
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOST.cpp
+
+ OpenSSL GOST R 34.10-2001 asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "OSSLGOST.h"
+#include "OSSLCryptoFactory.h"
+#include "ECParameters.h"
+#include "OSSLGOSTKeyPair.h"
+#include "OSSLGOSTPrivateKey.h"
+#include "OSSLGOSTPublicKey.h"
+#include "OSSLComp.h"
+#include <algorithm>
+#include <openssl/ecdsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <string.h>
+
+// Destructor
+OSSLGOST::~OSSLGOST()
+{
+       EVP_MD_CTX_free(curCTX);
+}
+
+// Signing functions
+bool OSSLGOST::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                   ByteString& signature, const AsymMech::Type mechanism,
+                   const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::GOST)
+       {
+               // Separate implementation for GOST signing without hash computation
+
+               // Check if the private key is the right type
+               if (!privateKey->isOfType(OSSLGOSTPrivateKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // In case of raw GOST, the length of the input data must be 32 bytes
+               if (dataToSign.size() != 32)
+               {
+                       ERROR_MSG("Size of data to sign is not 32 bytes");
+
+                       return false;
+               }
+
+               // Perform the signature operation
+               OSSLGOSTPrivateKey* osslKey = (OSSLGOSTPrivateKey*) privateKey;
+               EVP_PKEY* pkey = osslKey->getOSSLKey();
+               size_t outLen;
+
+               if (pkey == NULL)
+               {
+                       ERROR_MSG("Could not get the OpenSSL private key");
+
+                       return false;
+               }
+
+               signature.resize(EVP_PKEY_size(pkey));
+               outLen = signature.size();
+
+               EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey,NULL);
+               if (ctx == NULL)
+               {
+                       ERROR_MSG("EVP_PKEY_CTX_new failed");
+                       return false;
+               }
+
+               if (EVP_PKEY_sign_init(ctx) <= 0)
+               {
+                       ERROR_MSG("EVP_PKEY_sign_init failed");
+                       EVP_PKEY_CTX_free(ctx);
+                       return false;
+               }
+
+               if (EVP_PKEY_sign(ctx, &signature[0], &outLen, dataToSign.const_byte_str(), dataToSign.size()) <= 0)
+               {
+                       ERROR_MSG("An error occurred while performing a signature");
+                       EVP_PKEY_CTX_free(ctx);
+                       return false;
+               }
+
+               signature.resize(outLen);
+               EVP_PKEY_CTX_free(ctx);
+
+               return true;
+       }
+       else
+       {
+               // Call default implementation
+               return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLGOST::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                       const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(OSSLGOSTPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       if (mechanism != AsymMech::GOST_GOST)
+       {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       curCTX = EVP_MD_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_MD_CTX");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       const EVP_MD* md = OSSLCryptoFactory::i()->EVP_GOST_34_11;
+       if (!EVP_DigestInit_ex(curCTX, md, NULL))
+       {
+               ERROR_MSG("EVP_DigestInit_ex failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLGOST::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       if (!EVP_DigestUpdate(curCTX, dataToSign.const_byte_str(), dataToSign.size()))
+       {
+               ERROR_MSG("EVP_DigestUpdate failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLGOST::signFinal(ByteString& signature)
+{
+       // Save necessary state before calling super class signFinal
+       OSSLGOSTPrivateKey* pk = (OSSLGOSTPrivateKey*) currentPrivateKey;
+
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the signature operation
+       EVP_PKEY* pkey = pk->getOSSLKey();
+       unsigned int outLen;
+
+       if (pkey == NULL)
+       {
+               ERROR_MSG("Could not get the OpenSSL private key");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       signature.resize(EVP_PKEY_size(pkey));
+       outLen = signature.size();
+       if (!EVP_SignFinal(curCTX, &signature[0], &outLen, pkey))
+       {
+               ERROR_MSG("EVP_SignFinal failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       signature.resize(outLen);
+
+       EVP_MD_CTX_free(curCTX);
+       curCTX = NULL;
+
+       return true;
+}
+
+// Verification functions
+bool OSSLGOST::verify(PublicKey* publicKey, const ByteString& originalData,
+                     const ByteString& signature, const AsymMech::Type mechanism,
+                     const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::GOST)
+       {
+               // Separate implementation for GOST verification without hash computation
+
+               // Check if the private key is the right type
+               if (!publicKey->isOfType(OSSLGOSTPublicKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // Perform the verification operation
+               OSSLGOSTPublicKey* osslKey = (OSSLGOSTPublicKey*) publicKey;
+               EVP_PKEY* pkey = osslKey->getOSSLKey();
+
+               if (pkey == NULL)
+               {
+                       ERROR_MSG("Could not get the OpenSSL public key");
+
+                       return false;
+               }
+
+               EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey,NULL);
+               if (ctx == NULL)
+               {
+                       ERROR_MSG("EVP_PKEY_CTX_new failed");
+                       return false;
+               }
+
+               if (EVP_PKEY_verify_init(ctx) <= 0)
+               {
+                       ERROR_MSG("EVP_PKEY_verify_init failed");
+                       EVP_PKEY_CTX_free(ctx);
+                       return false;
+               }
+
+               int ret = EVP_PKEY_verify(ctx, signature.const_byte_str(), signature.size(), originalData.const_byte_str(), originalData.size());
+               EVP_PKEY_CTX_free(ctx);
+               if (ret != 1)
+               {
+                       if (ret < 0)
+                               ERROR_MSG("GOST verify failed (0x%08X)", ERR_get_error());
+
+                       return false;
+               }
+               return true;
+       }
+       else
+       {
+               // Call the generic function
+               return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLGOST::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                         const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(OSSLGOSTPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       if (mechanism != AsymMech::GOST_GOST)
+       {
+               ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       curCTX = EVP_MD_CTX_new();
+       if (curCTX == NULL)
+       {
+               ERROR_MSG("Failed to allocate space for EVP_MD_CTX");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       const EVP_MD* md = OSSLCryptoFactory::i()->EVP_GOST_34_11;
+       if (!EVP_DigestInit_ex(curCTX, md, NULL))
+       {
+               ERROR_MSG("EVP_DigestInit_ex failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLGOST::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       if (!EVP_DigestUpdate(curCTX, originalData.const_byte_str(), originalData.size()))
+       {
+               ERROR_MSG("EVP_DigestUpdate failed");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLGOST::verifyFinal(const ByteString& signature)
+{
+       // Save necessary state before calling super class verifyFinal
+       OSSLGOSTPublicKey* pk = (OSSLGOSTPublicKey*) currentPublicKey;
+
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       // Perform the verify operation
+       EVP_PKEY *pkey = pk->getOSSLKey();
+       int ret;
+
+       if (pkey == NULL)
+       {
+               ERROR_MSG("Could not get the OpenSSL public key");
+
+               EVP_MD_CTX_free(curCTX);
+               curCTX = NULL;
+
+               return false;
+       }
+
+       ret = EVP_VerifyFinal(curCTX, signature.const_byte_str(), signature.size(), pkey);
+       EVP_MD_CTX_free(curCTX);
+       curCTX = NULL;
+       if (ret != 1)
+       {
+               if (ret < 0)
+                       ERROR_MSG("GOST verify failed (0x%08X)", ERR_get_error());
+
+               return false;
+       }
+       return true;
+}
+
+// Encryption functions
+bool OSSLGOST::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+                      ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("GOST does not support encryption");
+
+       return false;
+}
+
+// Decryption functions
+bool OSSLGOST::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+                      ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+       ERROR_MSG("GOST does not support decryption");
+
+       return false;
+}
+
+// Key factory
+bool OSSLGOST::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(ECParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for GOST key generation");
+
+               return false;
+       }
+
+       ECParameters* params = (ECParameters*) parameters;
+       ByteString paramA = "06072a850302022301";
+       if (params->getEC() != paramA)
+       {
+               ERROR_MSG("unsupported parameters");
+
+               return false;
+       }
+
+       // Generate the key-pair
+       EVP_PKEY_CTX* ctx = NULL;
+       EVP_PKEY* pkey = NULL;
+       OSSLGOSTKeyPair* kp;
+
+       ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
+       if (ctx == NULL)
+       {
+               ERROR_MSG("EVP_PKEY_CTX_new_id failed");
+
+               goto err;
+       }
+       if (EVP_PKEY_keygen_init(ctx) <= 0)
+       {
+               ERROR_MSG("EVP_PKEY_keygen_init failed");
+
+               goto err;
+       }
+       if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
+       {
+               ERROR_MSG("EVP_PKEY_CTX_ctrl_str failed");
+
+               goto err;
+       }
+       if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+       {
+               ERROR_MSG("EVP_PKEY_keygen failed");
+
+               goto err;
+       }
+       EVP_PKEY_CTX_free(ctx);
+       ctx = NULL;
+
+       // Create an asymmetric key-pair object to return
+       kp = new OSSLGOSTKeyPair();
+
+       ((OSSLGOSTPublicKey*) kp->getPublicKey())->setFromOSSL(pkey);
+       ((OSSLGOSTPrivateKey*) kp->getPrivateKey())->setFromOSSL(pkey);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       EVP_PKEY_free(pkey);
+
+       return true;
+
+err:
+       if (ctx != NULL)
+               EVP_PKEY_CTX_free(ctx);
+       if (pkey != NULL)
+               EVP_PKEY_free(pkey);
+
+       return false;
+}
+
+unsigned long OSSLGOST::getMinKeySize()
+{
+       return 0;
+}
+
+unsigned long OSSLGOST::getMaxKeySize()
+{
+       return 0;
+}
+
+bool OSSLGOST::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLGOSTKeyPair* kp = new OSSLGOSTKeyPair();
+
+       bool rv = true;
+
+       if (!((OSSLGOSTPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((OSSLGOSTPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLGOST::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLGOSTPublicKey* pub = new OSSLGOSTPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLGOST::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLGOSTPrivateKey* priv = new OSSLGOSTPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLGOST::newPublicKey()
+{
+       return (PublicKey*) new OSSLGOSTPublicKey();
+}
+
+PrivateKey* OSSLGOST::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLGOSTPrivateKey();
+}
+
+AsymmetricParameters* OSSLGOST::newParameters()
+{
+       return (AsymmetricParameters*) new ECParameters();
+}
+
+bool OSSLGOST::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ECParameters* params = new ECParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOST.h b/SoftHSMv2/src/lib/crypto/OSSLGOST.h
new file mode 100644 (file)
index 0000000..ad399f1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOST.h
+
+ OpenSSL GOST R 34.10-2001 asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLGOST_H
+#define _SOFTHSM_V2_OSSLGOST_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLGOST : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       OSSLGOST() : AsymmetricAlgorithm() {
+               curCTX = NULL;
+       }
+
+       // Destructor
+       ~OSSLGOST();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       EVP_MD_CTX* curCTX;
+};
+
+#endif // !_SOFTHSM_V2_OSSLGOST_H
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp b/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp
new file mode 100644 (file)
index 0000000..969a216
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTKeyPair.cpp
+
+ OpenSSL GOST R 34.10-2001 key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "OSSLGOSTKeyPair.h"
+
+// Set the public key
+void OSSLGOSTKeyPair::setPublicKey(OSSLGOSTPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void OSSLGOSTKeyPair::setPrivateKey(OSSLGOSTPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* OSSLGOSTKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* OSSLGOSTKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* OSSLGOSTKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* OSSLGOSTKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h b/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h
new file mode 100644 (file)
index 0000000..b064704
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTKeyPair.h
+
+ OpenSSL GOST R 34.10-2001 key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLGOSTKEYPAIR_H
+#define _SOFTHSM_V2_OSSLGOSTKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "OSSLGOSTPublicKey.h"
+#include "OSSLGOSTPrivateKey.h"
+
+class OSSLGOSTKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(OSSLGOSTPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(OSSLGOSTPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       OSSLGOSTPublicKey pubKey;
+
+       // The private key
+       OSSLGOSTPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLGOSTKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp
new file mode 100644 (file)
index 0000000..6371e8f
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTPrivateKey.cpp
+
+ OpenSSL GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "OSSLGOSTPrivateKey.h"
+#include "OSSLUtil.h"
+#include <string.h>
+#include <openssl/ec.h>
+
+// DER of a private key
+const unsigned char dummyKey[] = {
+       0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
+       0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
+       0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
+       0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
+       0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b,
+       0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5,
+       0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65,
+       0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63,
+       0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6
+};
+
+// Constructors
+OSSLGOSTPrivateKey::OSSLGOSTPrivateKey()
+{
+       pkey = EVP_PKEY_new();
+}
+
+OSSLGOSTPrivateKey::OSSLGOSTPrivateKey(const EVP_PKEY* inPKEY)
+{
+       OSSLGOSTPrivateKey();
+
+       setFromOSSL(inPKEY);
+}
+
+// Destructor
+OSSLGOSTPrivateKey::~OSSLGOSTPrivateKey()
+{
+       EVP_PKEY_free(pkey);
+}
+
+// The type
+/*static*/ const char* OSSLGOSTPrivateKey::type = "OpenSSL GOST Private Key";
+
+// Get the output length
+unsigned long OSSLGOSTPrivateKey::getOutputLength() const
+{
+       return 64;
+}
+
+// Set from OpenSSL representation
+void OSSLGOSTPrivateKey::setFromOSSL(const EVP_PKEY* pkey)
+{
+       const EC_KEY* eckey = (const EC_KEY*) EVP_PKEY_get0((EVP_PKEY*) pkey);
+       const BIGNUM* priv = EC_KEY_get0_private_key(eckey);
+       setD(OSSL::bn2ByteString(priv));
+
+       ByteString inEC;
+       int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
+       inEC.resize(i2d_ASN1_OBJECT(OBJ_nid2obj(nid), NULL));
+       unsigned char *p = &inEC[0];
+       i2d_ASN1_OBJECT(OBJ_nid2obj(nid), &p);
+       setEC(inEC);
+}
+
+// Check if the key is of the given type
+bool OSSLGOSTPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the GOST private key components
+void OSSLGOSTPrivateKey::setD(const ByteString& inD)
+{
+       GOSTPrivateKey::setD(inD);
+
+       EC_KEY* inEC = (EC_KEY*) EVP_PKEY_get0((EVP_PKEY*) pkey);
+       if (inEC == NULL)
+       {
+               const unsigned char* p = dummyKey;
+               if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, (long) sizeof(dummyKey)) == NULL)
+               {
+                       ERROR_MSG("d2i_PrivateKey failed");
+
+                       return;
+               }
+               inEC = (EC_KEY*) EVP_PKEY_get0((EVP_PKEY*) pkey);
+       }
+
+       const BIGNUM* priv = OSSL::byteString2bn(inD);
+       if (EC_KEY_set_private_key(inEC, priv) <= 0)
+       {
+               ERROR_MSG("EC_KEY_set_private_key failed");
+               return;
+       }
+       BN_clear_free((BIGNUM*)priv);
+
+#ifdef notyet
+       if (gost2001_compute_public(inEC) <= 0)
+               ERROR_MSG("gost2001_compute_public failed");
+#endif
+}
+
+// Setters for the GOST public key components
+void OSSLGOSTPrivateKey::setEC(const ByteString& inEC)
+{
+        GOSTPrivateKey::setEC(inEC);
+}
+
+// Retrieve the OpenSSL representation of the key
+EVP_PKEY* OSSLGOSTPrivateKey::getOSSLKey()
+{
+       return pkey;
+}
+
+// Serialisation
+ByteString OSSLGOSTPrivateKey::serialise() const
+{
+       return ec.serialise() +
+              d.serialise();
+}
+
+bool OSSLGOSTPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dD = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dD.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setD(dD);
+
+       return true;
+}
+
+// Encode into PKCS#8 DER
+ByteString OSSLGOSTPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       // TODO
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool OSSLGOSTPrivateKey::PKCS8Decode(const ByteString& /*ber*/)
+{
+       return false;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h b/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h
new file mode 100644 (file)
index 0000000..eca0f13
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTPrivateKey.h
+
+ OpenSSL GOST R 34.10-2001 private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLGOSTPRIVATEKEY_H
+#define _SOFTHSM_V2_OSSLGOSTPRIVATEKEY_H
+
+#include "config.h"
+#include "GOSTPrivateKey.h"
+#include <openssl/evp.h>
+
+class OSSLGOSTPrivateKey : public GOSTPrivateKey
+{
+public:
+       // Constructors
+       OSSLGOSTPrivateKey();
+
+       OSSLGOSTPrivateKey(const EVP_PKEY* inPKEY);
+
+       // Destructor
+       virtual ~OSSLGOSTPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the GOST private key components
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the GOST public key components
+       virtual void setEC(const ByteString& inEC);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const EVP_PKEY* pkey);
+
+       // Retrieve the OpenSSL representation of the key
+       EVP_PKEY* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       EVP_PKEY* pkey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLGOSTPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp
new file mode 100644 (file)
index 0000000..5810637
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTPublicKey.cpp
+
+ OpenSSL GOST R 34.10-2001 public key class
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "log.h"
+#include "OSSLGOSTPublicKey.h"
+#include <openssl/x509.h>
+#include <string.h>
+
+// the 37 bytes of prefix
+const unsigned char gost_prefix[] = {
+       0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
+       0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
+       0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
+       0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
+       0x03, 0x43, 0x00, 0x04, 0x40
+};
+
+// Constructors
+OSSLGOSTPublicKey::OSSLGOSTPublicKey()
+{
+       pkey = EVP_PKEY_new();
+}
+
+OSSLGOSTPublicKey::OSSLGOSTPublicKey(const EVP_PKEY* inPKEY)
+{
+       OSSLGOSTPublicKey();
+
+       setFromOSSL(inPKEY);
+}
+
+// Destructor
+OSSLGOSTPublicKey::~OSSLGOSTPublicKey()
+{
+       EVP_PKEY_free(pkey);
+}
+
+// The type
+/*static*/ const char* OSSLGOSTPublicKey::type = "OpenSSL GOST Public Key";
+
+// Get the output length
+unsigned long OSSLGOSTPublicKey::getOutputLength() const
+{
+       return getQ().size();
+}
+
+// Set from OpenSSL representation
+void OSSLGOSTPublicKey::setFromOSSL(const EVP_PKEY* pkey)
+{
+       ByteString der;
+       int len = i2d_PUBKEY((EVP_PKEY*) pkey, NULL);
+       if (len != 37 + 64)
+       {
+               ERROR_MSG("bad GOST public key encoding length %d", len);
+               return;
+       }
+       der.resize(len);
+       unsigned char *p = &der[0];
+       i2d_PUBKEY((EVP_PKEY*) pkey, &p);
+       // can check: der is prefix + 64 bytes
+       setQ(der.substr(37));
+
+       ByteString inEC;
+       const EC_KEY* eckey = (const EC_KEY*) EVP_PKEY_get0((EVP_PKEY*) pkey);
+       int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
+       inEC.resize(i2d_ASN1_OBJECT(OBJ_nid2obj(nid), NULL));
+       p = &inEC[0];
+       i2d_ASN1_OBJECT(OBJ_nid2obj(nid), &p);
+       setEC(inEC);
+}
+
+// Check if the key is of the given type
+bool OSSLGOSTPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the GOST public key components
+void OSSLGOSTPublicKey::setEC(const ByteString& inEC)
+{
+        GOSTPublicKey::setEC(inEC);
+}
+
+void OSSLGOSTPublicKey::setQ(const ByteString& inQ)
+{
+       GOSTPublicKey::setQ(inQ);
+
+       if (inQ.size() != 64)
+       {
+               ERROR_MSG("bad GOST public key size %zu", q.size());
+               return;
+       }
+
+       ByteString der;
+       der.resize(37 + 64);
+       memcpy(&der[0], gost_prefix, 37);
+       memcpy(&der[37], inQ.const_byte_str(), 64);
+       const unsigned char *p = &der[0];
+       if (d2i_PUBKEY(&pkey, &p, (long) der.size()) == NULL)
+               ERROR_MSG("d2i_PUBKEY failed");
+}
+
+// Serialisation
+ByteString OSSLGOSTPublicKey::serialise() const
+{
+       return ec.serialise() +
+              q.serialise();
+}
+
+bool OSSLGOSTPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dEC = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+
+       if ((dEC.size() == 0) ||
+           (dQ.size() == 0))
+       {
+               return false;
+       }
+
+       setEC(dEC);
+       setQ(dQ);
+
+       return true;
+}
+
+// Retrieve the OpenSSL representation of the key
+EVP_PKEY* OSSLGOSTPublicKey::getOSSLKey()
+{
+       return pkey;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h b/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h
new file mode 100644 (file)
index 0000000..c951962
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTPublicKey.h
+
+ OpenSSL GOST R 34.10-2001 public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLGOSTPUBLICKEY_H
+#define _SOFTHSM_V2_OSSLGOSTPUBLICKEY_H
+
+#include "config.h"
+#include "GOSTPublicKey.h"
+#include <openssl/evp.h>
+
+class OSSLGOSTPublicKey : public GOSTPublicKey
+{
+public:
+       // Constructors
+       OSSLGOSTPublicKey();
+
+       OSSLGOSTPublicKey(const EVP_PKEY* inPKEY);
+
+       // Destructor
+       virtual ~OSSLGOSTPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the GOST public key components
+       virtual void setEC(const ByteString& inEC);
+       virtual void setQ(const ByteString& inQ);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const EVP_PKEY* pkey);
+
+       // Retrieve the OpenSSL representation of the key
+       EVP_PKEY* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       EVP_PKEY* pkey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp b/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp
new file mode 100644 (file)
index 0000000..5361075
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTR3411.h
+
+ OpenSSL GOST R 34.11-94 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_GOST
+#include "OSSLGOSTR3411.h"
+#include "OSSLCryptoFactory.h"
+#include <openssl/evp.h>
+
+int OSSLGOSTR3411::getHashSize()
+{
+       return 32;
+}
+
+const EVP_MD* OSSLGOSTR3411::getEVPHash() const
+{
+       return OSSLCryptoFactory::i()->EVP_GOST_34_11;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h b/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h
new file mode 100644 (file)
index 0000000..8175258
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLGOSTR3411.h
+
+ OpenSSL GOST R 34.11-94 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLGOSTR3411_H
+#define _SOFTHSM_V2_OSSLGOSTR3411_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLGOSTR3411 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLGOSTR3411_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp b/SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp
new file mode 100644 (file)
index 0000000..f8b73a7
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLHMAC.cpp
+
+ OpenSSL HMAC implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLHMAC.h"
+#ifdef WITH_GOST
+#include "OSSLCryptoFactory.h"
+#endif
+
+const EVP_MD* OSSLHMACMD5::getEVPHash() const
+{
+       return EVP_md5();
+}
+
+size_t OSSLHMACMD5::getMacSize() const
+{
+       return 16;
+}
+
+const EVP_MD* OSSLHMACSHA1::getEVPHash() const
+{
+       return EVP_sha1();
+}
+
+size_t OSSLHMACSHA1::getMacSize() const
+{
+       return 20;
+}
+
+const EVP_MD* OSSLHMACSHA224::getEVPHash() const
+{
+       return EVP_sha224();
+}
+
+size_t OSSLHMACSHA224::getMacSize() const
+{
+       return 28;
+}
+
+const EVP_MD* OSSLHMACSHA256::getEVPHash() const
+{
+       return EVP_sha256();
+}
+
+size_t OSSLHMACSHA256::getMacSize() const
+{
+       return 32;
+}
+
+const EVP_MD* OSSLHMACSHA384::getEVPHash() const
+{
+       return EVP_sha384();
+}
+
+size_t OSSLHMACSHA384::getMacSize() const
+{
+       return 48;
+}
+
+const EVP_MD* OSSLHMACSHA512::getEVPHash() const
+{
+       return EVP_sha512();
+}
+
+size_t OSSLHMACSHA512::getMacSize() const
+{
+       return 64;
+}
+
+#ifdef WITH_GOST
+const EVP_MD* OSSLHMACGOSTR3411::getEVPHash() const
+{
+       return OSSLCryptoFactory::i()->EVP_GOST_34_11;
+}
+
+size_t OSSLHMACGOSTR3411::getMacSize() const
+{
+       return 32;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLHMAC.h b/SoftHSMv2/src/lib/crypto/OSSLHMAC.h
new file mode 100644 (file)
index 0000000..852614e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLHMAC.h
+
+ OpenSSL HMAC implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLHMAC_H
+#define _SOFTHSM_V2_OSSLHMAC_H
+
+#include "config.h"
+#include "OSSLEVPMacAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLHMACMD5 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLHMACSHA1 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLHMACSHA224 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLHMACSHA256 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLHMACSHA384 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+class OSSLHMACSHA512 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+
+#ifdef WITH_GOST
+class OSSLHMACGOSTR3411 : public OSSLEVPMacAlgorithm
+{
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+       virtual size_t getMacSize() const;
+};
+#endif
+
+#endif // !_SOFTHSM_V2_OSSLHMAC_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLMD5.cpp b/SoftHSMv2/src/lib/crypto/OSSLMD5.cpp
new file mode 100644 (file)
index 0000000..2c962a6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLMD5.h
+
+ OpenSSL MD5 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLMD5.h"
+#include <openssl/evp.h>
+
+int OSSLMD5::getHashSize()
+{
+       return 16;
+}
+
+const EVP_MD* OSSLMD5::getEVPHash() const
+{
+       return EVP_md5();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLMD5.h b/SoftHSMv2/src/lib/crypto/OSSLMD5.h
new file mode 100644 (file)
index 0000000..22d7111
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLMD5.h
+
+ OpenSSL MD5 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLMD5_H
+#define _SOFTHSM_V2_OSSLMD5_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLMD5 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLMD5_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRNG.cpp b/SoftHSMv2/src/lib/crypto/OSSLRNG.cpp
new file mode 100644 (file)
index 0000000..d6a1e5d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRNG.cpp
+
+ OpenSSL random number generator class
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLRNG.h"
+#include <openssl/rand.h>
+
+// Generate random data
+bool OSSLRNG::generateRandom(ByteString& data, const size_t len)
+{
+       data.wipe(len);
+
+       if (len == 0)
+               return true;
+       return RAND_bytes(&data[0], len) == 1;
+}
+
+// Seed the random pool
+void OSSLRNG::seed(ByteString& seedData)
+{
+       RAND_seed(seedData.byte_str(), seedData.size());
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRNG.h b/SoftHSMv2/src/lib/crypto/OSSLRNG.h
new file mode 100644 (file)
index 0000000..829f593
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRNG.h
+
+ OpenSSL random number generator class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLRNG_H
+#define _SOFTHSM_V2_OSSLRNG_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "RNG.h"
+
+class OSSLRNG : public RNG
+{
+public:
+       // Generate random data
+       virtual bool generateRandom(ByteString& data, const size_t len);
+
+       // Seed the random pool
+       virtual void seed(ByteString& seedData);
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_OSSLRNG_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSA.cpp b/SoftHSMv2/src/lib/crypto/OSSLRSA.cpp
new file mode 100644 (file)
index 0000000..1e5638a
--- /dev/null
@@ -0,0 +1,1554 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSA.cpp
+
+ OpenSSL RSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLRSA.h"
+#include "OSSLUtil.h"
+#include "CryptoFactory.h"
+#include "RSAParameters.h"
+#include "OSSLRSAKeyPair.h"
+#include <algorithm>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+// Constructor
+OSSLRSA::OSSLRSA()
+{
+       pCurrentHash = NULL;
+       pSecondHash = NULL;
+       sLen = 0;
+}
+
+// Destructor
+OSSLRSA::~OSSLRSA()
+{
+       if (pCurrentHash != NULL)
+       {
+               delete pCurrentHash;
+       }
+
+       if (pSecondHash != NULL)
+       {
+               delete pSecondHash;
+       }
+}
+
+// Signing functions
+bool OSSLRSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+                  ByteString& signature, const AsymMech::Type mechanism,
+                  const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::RSA_PKCS)
+       {
+               // Separate implementation for RSA PKCS #1 signing without hash computation
+
+               // Check if the private key is the right type
+               if (!privateKey->isOfType(OSSLRSAPrivateKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // In case of PKCS #1 signing the length of the input data may not exceed 40% of the
+               // modulus size
+               OSSLRSAPrivateKey* osslKey = (OSSLRSAPrivateKey*) privateKey;
+
+               size_t allowedLen = osslKey->getN().size() - 11;
+
+               if (dataToSign.size() > allowedLen)
+               {
+                       ERROR_MSG("Data to sign exceeds maximum for PKCS #1 signature");
+
+                       return false;
+               }
+
+               // Perform the signature operation
+               signature.resize(osslKey->getN().size());
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               if (!RSA_blinding_on(rsa, NULL))
+               {
+                       ERROR_MSG("Failed to turn on blinding for OpenSSL RSA key");
+
+                       return false;
+               }
+
+               int sigLen = RSA_private_encrypt(dataToSign.size(), (unsigned char*) dataToSign.const_byte_str(), &signature[0], rsa, RSA_PKCS1_PADDING);
+
+               RSA_blinding_off(rsa);
+
+               if (sigLen == -1)
+               {
+                       ERROR_MSG("An error occurred while performing a PKCS #1 signature");
+
+                       return false;
+               }
+
+               signature.resize(sigLen);
+
+               return true;
+       }
+       else if (mechanism == AsymMech::RSA_PKCS_PSS)
+       {
+               const RSA_PKCS_PSS_PARAMS *pssParam = (RSA_PKCS_PSS_PARAMS*)param;
+
+               // Separate implementation for RSA PKCS #1 signing without hash computation
+
+               // Check if the private key is the right type
+               if (!privateKey->isOfType(OSSLRSAPrivateKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               if (pssParam == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS))
+               {
+                       ERROR_MSG("Invalid parameters supplied");
+
+                       return false;
+               }
+
+               size_t allowedLen;
+               const EVP_MD* hash = NULL;
+
+               switch (pssParam->hashAlg)
+               {
+               case HashAlgo::SHA1:
+                       hash = EVP_sha1();
+                       allowedLen = 20;
+                       break;
+               case HashAlgo::SHA224:
+                       hash = EVP_sha224();
+                       allowedLen = 28;
+                       break;
+               case HashAlgo::SHA256:
+                       hash = EVP_sha256();
+                       allowedLen = 32;
+                       break;
+               case HashAlgo::SHA384:
+                       hash = EVP_sha384();
+                       allowedLen = 48;
+                       break;
+               case HashAlgo::SHA512:
+                       hash = EVP_sha512();
+                       allowedLen = 64;
+                       break;
+               default:
+                       return false;
+               }
+
+               OSSLRSAPrivateKey* osslKey = (OSSLRSAPrivateKey*) privateKey;
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               if (dataToSign.size() != allowedLen)
+               {
+                       ERROR_MSG("Data to sign does not match expected (%d) for RSA PSS", (int)allowedLen);
+
+                       return false;
+               }
+
+               size_t sLen = pssParam->sLen;
+               if (sLen > ((privateKey->getBitLength()+6)/8-2-allowedLen))
+               {
+                       ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                 (unsigned long)sLen, privateKey->getBitLength());
+                       return false;
+               }
+
+               ByteString em;
+               em.resize(osslKey->getN().size());
+
+               int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, &em[0], (unsigned char*) dataToSign.const_byte_str(), hash, hash, pssParam->sLen);
+               if (!status)
+               {
+                       ERROR_MSG("Error in RSA PSS padding generation");
+
+                       return false;
+               }
+
+
+               if (!RSA_blinding_on(rsa, NULL))
+               {
+                       ERROR_MSG("Failed to turn on blinding for OpenSSL RSA key");
+
+                       return false;
+               }
+
+               // Perform the signature operation
+               signature.resize(osslKey->getN().size());
+
+               int sigLen = RSA_private_encrypt(osslKey->getN().size(), &em[0], &signature[0], rsa, RSA_NO_PADDING);
+
+               RSA_blinding_off(rsa);
+
+               if (sigLen == -1)
+               {
+                       ERROR_MSG("An error occurred while performing the RSA-PSS signature");
+
+                       return false;
+               }
+
+               signature.resize(sigLen);
+
+               return true;
+       }
+       else if (mechanism == AsymMech::RSA)
+       {
+               // Separate implementation for raw RSA signing
+
+               // Check if the private key is the right type
+               if (!privateKey->isOfType(OSSLRSAPrivateKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // In case of raw RSA, the length of the input data must match the length of the modulus
+               OSSLRSAPrivateKey* osslKey = (OSSLRSAPrivateKey*) privateKey;
+
+               if (dataToSign.size() != osslKey->getN().size())
+               {
+                       ERROR_MSG("Size of data to sign does not match the modulus size");
+
+                       return false;
+               }
+
+               // Perform the signature operation
+               signature.resize(osslKey->getN().size());
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               if (!RSA_blinding_on(rsa, NULL))
+               {
+                       ERROR_MSG("Failed to turn on blinding for OpenSSL RSA key");
+
+                       return false;
+               }
+
+               int sigLen = RSA_private_encrypt(dataToSign.size(), (unsigned char*) dataToSign.const_byte_str(), &signature[0], rsa, RSA_NO_PADDING);
+
+               RSA_blinding_off(rsa);
+
+               if (sigLen == -1)
+               {
+                       ERROR_MSG("An error occurred while performing a raw RSA signature");
+
+                       return false;
+               }
+
+               signature.resize(sigLen);
+
+               return true;
+       }
+       else
+       {
+               // Call default implementation
+               return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLRSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+                      const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(OSSLRSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       HashAlgo::Type hash1 = HashAlgo::Unknown;
+       HashAlgo::Type hash2 = HashAlgo::Unknown;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       hash1 = HashAlgo::MD5;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       hash1 = HashAlgo::SHA1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       hash1 = HashAlgo::SHA224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       hash1 = HashAlgo::SHA256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       hash1 = HashAlgo::SHA384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       hash1 = HashAlgo::SHA512;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-20))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-28))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-32))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-48))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((privateKey->getBitLength()+6)/8-2-64))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, privateKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::signFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA512;
+                       break;
+               case AsymMech::RSA_SSL:
+                       hash1 = HashAlgo::MD5;
+                       hash2 = HashAlgo::SHA1;
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+       }
+
+       pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash1);
+
+       if (pCurrentHash == NULL || !pCurrentHash->hashInit())
+       {
+               if (pCurrentHash != NULL)
+               {
+                       delete pCurrentHash;
+                       pCurrentHash = NULL;
+               }
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       if (hash2 != HashAlgo::Unknown)
+       {
+               pSecondHash = CryptoFactory::i()->getHashAlgorithm(hash2);
+
+               if (pSecondHash == NULL || !pSecondHash->hashInit())
+               {
+                       delete pCurrentHash;
+                       pCurrentHash = NULL;
+
+                       if (pSecondHash != NULL)
+                       {
+                               delete pSecondHash;
+                               pSecondHash = NULL;
+                       }
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::signFinal(dummy);
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool OSSLRSA::signUpdate(const ByteString& dataToSign)
+{
+       if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+       {
+               return false;
+       }
+
+       if (!pCurrentHash->hashUpdate(dataToSign))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       if ((pSecondHash != NULL) && !pSecondHash->hashUpdate(dataToSign))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               delete pSecondHash;
+               pSecondHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::signFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLRSA::signFinal(ByteString& signature)
+{
+       // Save necessary state before calling super class signFinal
+       OSSLRSAPrivateKey* pk = (OSSLRSAPrivateKey*) currentPrivateKey;
+       AsymMech::Type mechanism = currentMechanism;
+
+       if (!AsymmetricAlgorithm::signFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString firstHash, secondHash;
+
+       bool bFirstResult = pCurrentHash->hashFinal(firstHash);
+       bool bSecondResult = (pSecondHash != NULL) ? pSecondHash->hashFinal(secondHash) : true;
+
+       delete pCurrentHash;
+       pCurrentHash = NULL;
+
+       if (pSecondHash != NULL)
+       {
+               delete pSecondHash;
+
+               pSecondHash = NULL;
+       }
+
+       if (!bFirstResult || !bSecondResult)
+       {
+               return false;
+       }
+
+       ByteString digest = firstHash + secondHash;
+
+       // Resize the data block for the signature to the modulus size of the key
+       signature.resize(pk->getN().size());
+
+       // Determine the signature NID type
+       int type = 0;
+       bool isPSS = false;
+       const EVP_MD* hash = NULL;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       type = NID_md5;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       type = NID_sha1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       type = NID_sha224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       type = NID_sha256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       type = NID_sha384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       type = NID_sha512;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha1();
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha224();
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha256();
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha384();
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha512();
+                       break;
+               case AsymMech::RSA_SSL:
+                       type = NID_md5_sha1;
+                       break;
+               default:
+                       break;
+       }
+
+       // Perform the signature operation
+       unsigned int sigLen = signature.size();
+
+       RSA* rsa = pk->getOSSLKey();
+
+       if (!RSA_blinding_on(rsa, NULL))
+       {
+               ERROR_MSG("Failed to turn blinding on for OpenSSL RSA key");
+
+               return false;
+       }
+
+       bool rv;
+       int result;
+
+       if (isPSS)
+       {
+               ByteString em;
+               em.resize(pk->getN().size());
+
+               result = (RSA_padding_add_PKCS1_PSS(pk->getOSSLKey(), &em[0], &digest[0],
+                                               hash, sLen) == 1);
+               if (!result)
+               {
+                       ERROR_MSG("RSA PSS padding failed (0x%08X)", ERR_get_error());
+                       rv = false;
+               }
+               else
+               {
+                       result = RSA_private_encrypt(em.size(), &em[0], &signature[0],
+                                                        pk->getOSSLKey(), RSA_NO_PADDING);
+                       if (result >= 0)
+                       {
+                               sigLen = result;
+                               rv = true;
+                       }
+                       else
+                       {
+                               ERROR_MSG("RSA private encrypt failed (0x%08X)", ERR_get_error());
+                               rv = false;
+                       }
+               }
+       }
+       else
+       {
+               result = RSA_sign(type, &digest[0], digest.size(), &signature[0],
+                              &sigLen, pk->getOSSLKey());
+               if (result > 0)
+               {
+                       rv = true;
+               }
+               else
+               {
+                       ERROR_MSG("RSA sign failed (0x%08X)", ERR_get_error());
+                       rv = false;
+               }
+       }
+
+       RSA_blinding_off(rsa);
+
+       signature.resize(sigLen);
+
+       return rv;
+}
+
+// Verification functions
+bool OSSLRSA::verify(PublicKey* publicKey, const ByteString& originalData,
+                    const ByteString& signature, const AsymMech::Type mechanism,
+                    const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (mechanism == AsymMech::RSA_PKCS)
+       {
+               // Specific implementation for PKCS #1 only verification; originalData is assumed to contain
+               // a digestInfo structure and verification is performed by comparing originalData to the data
+               // recovered from the signature
+
+               // Check if the public key is the right type
+               if (!publicKey->isOfType(OSSLRSAPublicKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // Perform the RSA public key operation
+               OSSLRSAPublicKey* osslKey = (OSSLRSAPublicKey*) publicKey;
+
+               ByteString recoveredData;
+
+               recoveredData.resize(osslKey->getN().size());
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               int retLen = RSA_public_decrypt(signature.size(), (unsigned char*) signature.const_byte_str(), &recoveredData[0], rsa, RSA_PKCS1_PADDING);
+
+               if (retLen == -1)
+               {
+                       ERROR_MSG("Public key operation failed");
+
+                       return false;
+               }
+
+               recoveredData.resize(retLen);
+
+               return (originalData == recoveredData);
+       }
+       else if (mechanism == AsymMech::RSA_PKCS_PSS)
+       {
+               const RSA_PKCS_PSS_PARAMS *pssParam = (RSA_PKCS_PSS_PARAMS*)param;
+
+               if (pssParam == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS))
+               {
+                       ERROR_MSG("Invalid parameters supplied");
+
+                       return false;
+               }
+
+               // Check if the public key is the right type
+               if (!publicKey->isOfType(OSSLRSAPublicKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // Perform the RSA public key operation
+               OSSLRSAPublicKey* osslKey = (OSSLRSAPublicKey*) publicKey;
+
+               ByteString recoveredData;
+
+               recoveredData.resize(osslKey->getN().size());
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               int retLen = RSA_public_decrypt(signature.size(), (unsigned char*) signature.const_byte_str(), &recoveredData[0], rsa, RSA_NO_PADDING);
+
+               if (retLen == -1)
+               {
+                       ERROR_MSG("Public key operation failed");
+
+                       return false;
+               }
+
+               recoveredData.resize(retLen);
+
+               size_t allowedLen;
+               const EVP_MD* hash = NULL;
+
+               switch (pssParam->hashAlg)
+               {
+               case HashAlgo::SHA1:
+                       hash = EVP_sha1();
+                       allowedLen = 20;
+                       break;
+               case HashAlgo::SHA224:
+                       hash = EVP_sha224();
+                       allowedLen = 28;
+                       break;
+               case HashAlgo::SHA256:
+                       hash = EVP_sha256();
+                       allowedLen = 32;
+                       break;
+               case HashAlgo::SHA384:
+                       hash = EVP_sha384();
+                       allowedLen = 48;
+                       break;
+               case HashAlgo::SHA512:
+                       hash = EVP_sha512();
+                       allowedLen = 64;
+                       break;
+               default:
+                       return false;
+               }
+
+               if (originalData.size() != allowedLen) {
+                       return false;
+               }
+
+               size_t sLen = pssParam->sLen;
+               if (sLen > ((osslKey->getBitLength()+6)/8-2-allowedLen))
+               {
+                       ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                 (unsigned long)sLen, osslKey->getBitLength());
+                       return false;
+               }
+
+               int status = RSA_verify_PKCS1_PSS_mgf1(rsa, (unsigned char*)originalData.const_byte_str(), hash, hash, (unsigned char*) recoveredData.const_byte_str(), pssParam->sLen);
+
+               return (status == 1);
+       }
+       else if (mechanism == AsymMech::RSA)
+       {
+               // Specific implementation for raw RSA verifiction; originalData is assumed to contain the
+               // full input data used to compute the signature and verification is performed by comparing
+               // originalData to the data recovered from the signature
+
+               // Check if the public key is the right type
+               if (!publicKey->isOfType(OSSLRSAPublicKey::type))
+               {
+                       ERROR_MSG("Invalid key type supplied");
+
+                       return false;
+               }
+
+               // Perform the RSA public key operation
+               OSSLRSAPublicKey* osslKey = (OSSLRSAPublicKey*) publicKey;
+
+               ByteString recoveredData;
+
+               recoveredData.resize(osslKey->getN().size());
+
+               RSA* rsa = osslKey->getOSSLKey();
+
+               int retLen = RSA_public_decrypt(signature.size(), (unsigned char*) signature.const_byte_str(), &recoveredData[0], rsa, RSA_NO_PADDING);
+
+               if (retLen == -1)
+               {
+                       ERROR_MSG("Public key operation failed");
+
+                       return false;
+               }
+
+               recoveredData.resize(retLen);
+
+               return (originalData == recoveredData);
+       }
+       else
+       {
+               // Call the generic function
+               return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+       }
+}
+
+bool OSSLRSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+                        const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+       if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+       {
+               return false;
+       }
+
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(OSSLRSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       HashAlgo::Type hash1 = HashAlgo::Unknown;
+       HashAlgo::Type hash2 = HashAlgo::Unknown;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       hash1 = HashAlgo::MD5;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       hash1 = HashAlgo::SHA1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       hash1 = HashAlgo::SHA224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       hash1 = HashAlgo::SHA256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       hash1 = HashAlgo::SHA384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       hash1 = HashAlgo::SHA512;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-20))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-28))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-32))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-48))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 ||
+                           ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512)
+                       {
+                               ERROR_MSG("Invalid parameters");
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen;
+                       if (sLen > ((publicKey->getBitLength()+6)/8-2-64))
+                       {
+                               ERROR_MSG("sLen (%lu) is too large for current key size (%lu)",
+                                         (unsigned long)sLen, publicKey->getBitLength());
+                               ByteString dummy;
+                               AsymmetricAlgorithm::verifyFinal(dummy);
+                               return false;
+                       }
+                       hash1 = HashAlgo::SHA512;
+                       break;
+               case AsymMech::RSA_SSL:
+                       hash1 = HashAlgo::MD5;
+                       hash2 = HashAlgo::SHA1;
+                       break;
+               default:
+                       ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+       }
+
+       pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash1);
+
+       if (pCurrentHash == NULL || !pCurrentHash->hashInit())
+       {
+               if (pCurrentHash != NULL)
+               {
+                       delete pCurrentHash;
+                       pCurrentHash = NULL;
+               }
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       if (hash2 != HashAlgo::Unknown)
+       {
+               pSecondHash = CryptoFactory::i()->getHashAlgorithm(hash2);
+
+               if (pSecondHash == NULL || !pSecondHash->hashInit())
+               {
+                       delete pCurrentHash;
+                       pCurrentHash = NULL;
+
+                       if (pSecondHash != NULL)
+                       {
+                               delete pSecondHash;
+                               pSecondHash = NULL;
+                       }
+
+                       ByteString dummy;
+                       AsymmetricAlgorithm::verifyFinal(dummy);
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool OSSLRSA::verifyUpdate(const ByteString& originalData)
+{
+       if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+       {
+               return false;
+       }
+
+       if (!pCurrentHash->hashUpdate(originalData))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       if ((pSecondHash != NULL) && !pSecondHash->hashUpdate(originalData))
+       {
+               delete pCurrentHash;
+               pCurrentHash = NULL;
+
+               delete pSecondHash;
+               pSecondHash = NULL;
+
+               ByteString dummy;
+               AsymmetricAlgorithm::verifyFinal(dummy);
+
+               return false;
+       }
+
+       return true;
+}
+
+bool OSSLRSA::verifyFinal(const ByteString& signature)
+{
+       // Save necessary state before calling super class verifyFinal
+       OSSLRSAPublicKey* pk = (OSSLRSAPublicKey*) currentPublicKey;
+       AsymMech::Type mechanism = currentMechanism;
+
+       if (!AsymmetricAlgorithm::verifyFinal(signature))
+       {
+               return false;
+       }
+
+       ByteString firstHash, secondHash;
+
+       bool bFirstResult = pCurrentHash->hashFinal(firstHash);
+       bool bSecondResult = (pSecondHash != NULL) ? pSecondHash->hashFinal(secondHash) : true;
+
+       delete pCurrentHash;
+       pCurrentHash = NULL;
+
+       if (pSecondHash != NULL)
+       {
+               delete pSecondHash;
+
+               pSecondHash = NULL;
+       }
+
+       if (!bFirstResult || !bSecondResult)
+       {
+               return false;
+       }
+
+       ByteString digest = firstHash + secondHash;
+
+       // Determine the signature NID type
+       int type = 0;
+       bool isPSS = false;
+       const EVP_MD* hash = NULL;
+
+       switch (mechanism)
+       {
+               case AsymMech::RSA_MD5_PKCS:
+                       type = NID_md5;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS:
+                       type = NID_sha1;
+                       break;
+               case AsymMech::RSA_SHA224_PKCS:
+                       type = NID_sha224;
+                       break;
+               case AsymMech::RSA_SHA256_PKCS:
+                       type = NID_sha256;
+                       break;
+               case AsymMech::RSA_SHA384_PKCS:
+                       type = NID_sha384;
+                       break;
+               case AsymMech::RSA_SHA512_PKCS:
+                       type = NID_sha512;
+                       break;
+               case AsymMech::RSA_SHA1_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha1();
+                       break;
+               case AsymMech::RSA_SHA224_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha224();
+                       break;
+               case AsymMech::RSA_SHA256_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha256();
+                       break;
+               case AsymMech::RSA_SHA384_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha384();
+                       break;
+               case AsymMech::RSA_SHA512_PKCS_PSS:
+                       isPSS = true;
+                       hash = EVP_sha512();
+                       break;
+               case AsymMech::RSA_SSL:
+                       type = NID_md5_sha1;
+                       break;
+               default:
+                       break;
+       }
+
+       // Perform the verify operation
+       bool rv;
+
+       if (isPSS)
+       {
+               ByteString plain;
+               plain.resize(pk->getN().size());
+               int result = RSA_public_decrypt(signature.size(),
+                                               (unsigned char*) signature.const_byte_str(),
+                                               &plain[0],
+                                               pk->getOSSLKey(),
+                                               RSA_NO_PADDING);
+               if (result < 0)
+               {
+                       rv = false;
+                       ERROR_MSG("RSA public decrypt failed (0x%08X)", ERR_get_error());
+               }
+               else
+               {
+                       plain.resize(result);
+                       result = RSA_verify_PKCS1_PSS(pk->getOSSLKey(), &digest[0],
+                                                     hash, &plain[0], sLen);
+                       if (result == 1)
+                       {
+                               rv = true;
+                       }
+                       else
+                       {
+                               rv = false;
+                               ERROR_MSG("RSA PSS verify failed (0x%08X)", ERR_get_error());
+                       }
+               }
+       }
+       else
+       {
+               rv = (RSA_verify(type, &digest[0], digest.size(), (unsigned char*) signature.const_byte_str(), signature.size(), pk->getOSSLKey()) == 1);
+
+               if (!rv) ERROR_MSG("RSA verify failed (0x%08X)", ERR_get_error());
+       }
+
+       return rv;
+}
+
+// Encryption functions
+bool OSSLRSA::encrypt(PublicKey* publicKey, const ByteString& data,
+                     ByteString& encryptedData, const AsymMech::Type padding)
+{
+       // Check if the public key is the right type
+       if (!publicKey->isOfType(OSSLRSAPublicKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       // Retrieve the OpenSSL key object
+       RSA* rsa = ((OSSLRSAPublicKey*) publicKey)->getOSSLKey();
+
+       // Check the data and padding algorithm
+       int osslPadding = 0;
+
+       if (padding == AsymMech::RSA_PKCS)
+       {
+               // The size of the input data cannot be more than the modulus
+               // length of the key - 11
+               if (data.size() > (size_t) (RSA_size(rsa) - 11))
+               {
+                       ERROR_MSG("Too much data supplied for RSA PKCS #1 encryption");
+
+                       return false;
+               }
+
+               osslPadding = RSA_PKCS1_PADDING;
+       }
+       else if (padding == AsymMech::RSA_PKCS_OAEP)
+       {
+               // The size of the input data cannot be more than the modulus
+               // length of the key - 41
+               if (data.size() > (size_t) (RSA_size(rsa) - 41))
+               {
+                       ERROR_MSG("Too much data supplied for RSA OAEP encryption");
+
+                       return false;
+               }
+
+               osslPadding = RSA_PKCS1_OAEP_PADDING;
+       }
+       else if (padding == AsymMech::RSA)
+       {
+               // The size of the input data should be exactly equal to the modulus length
+               if (data.size() != (size_t) RSA_size(rsa))
+               {
+                       ERROR_MSG("Incorrect amount of input data supplied for raw RSA encryption");
+
+                       return false;
+               }
+
+               osslPadding = RSA_NO_PADDING;
+       }
+       else
+       {
+               ERROR_MSG("Invalid padding mechanism supplied (%i)", padding);
+
+               return false;
+       }
+
+       // Perform the RSA operation
+       encryptedData.resize(RSA_size(rsa));
+
+       if (RSA_public_encrypt(data.size(), (unsigned char*) data.const_byte_str(), &encryptedData[0], rsa, osslPadding) == -1)
+       {
+               ERROR_MSG("RSA public key encryption failed (0x%08X)", ERR_get_error());
+
+               return false;
+       }
+
+       return true;
+}
+
+// Decryption functions
+bool OSSLRSA::decrypt(PrivateKey* privateKey, const ByteString& encryptedData,
+                     ByteString& data, const AsymMech::Type padding)
+{
+       // Check if the private key is the right type
+       if (!privateKey->isOfType(OSSLRSAPrivateKey::type))
+       {
+               ERROR_MSG("Invalid key type supplied");
+
+               return false;
+       }
+
+       // Retrieve the OpenSSL key object
+       RSA* rsa = ((OSSLRSAPrivateKey*) privateKey)->getOSSLKey();
+
+       // Check the input size
+       if (encryptedData.size() != (size_t) RSA_size(rsa))
+       {
+               ERROR_MSG("Invalid amount of input data supplied for RSA decryption");
+
+               return false;
+       }
+
+       // Determine the OpenSSL padding algorithm
+       int osslPadding = 0;
+
+       switch (padding)
+       {
+               case AsymMech::RSA_PKCS:
+                       osslPadding = RSA_PKCS1_PADDING;
+                       break;
+               case AsymMech::RSA_PKCS_OAEP:
+                       osslPadding = RSA_PKCS1_OAEP_PADDING;
+                       break;
+               case AsymMech::RSA:
+                       osslPadding = RSA_NO_PADDING;
+                       break;
+               default:
+                       ERROR_MSG("Invalid padding mechanism supplied (%i)", padding);
+                       return false;
+       }
+
+       // Perform the RSA operation
+       data.resize(RSA_size(rsa));
+
+       int decSize = RSA_private_decrypt(encryptedData.size(), (unsigned char*) encryptedData.const_byte_str(), &data[0], rsa, osslPadding);
+
+       if (decSize == -1)
+       {
+               ERROR_MSG("RSA private key decryption failed (0x%08X)", ERR_get_error());
+
+               return false;
+       }
+
+       data.resize(decSize);
+
+       return true;
+}
+
+// Key factory
+bool OSSLRSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+       // Check parameters
+       if ((ppKeyPair == NULL) ||
+           (parameters == NULL))
+       {
+               return false;
+       }
+
+       if (!parameters->areOfType(RSAParameters::type))
+       {
+               ERROR_MSG("Invalid parameters supplied for RSA key generation");
+
+               return false;
+       }
+
+       RSAParameters* params = (RSAParameters*) parameters;
+
+       if (params->getBitLength() < getMinKeySize() || params->getBitLength() > getMaxKeySize())
+       {
+               ERROR_MSG("This RSA key size (%lu) is not supported", params->getBitLength());
+
+               return false;
+       }
+
+       if (params->getBitLength() < 1024)
+       {
+               WARNING_MSG("Using an RSA key size < 1024 bits is not recommended");
+       }
+
+       // Retrieve the desired public exponent
+       unsigned long e = params->getE().long_val();
+
+       // Check the public exponent
+       if ((e == 0) || (e % 2 != 1))
+       {
+               ERROR_MSG("Invalid RSA public exponent %d", e);
+
+               return false;
+       }
+
+       // Generate the key-pair
+       RSA* rsa = RSA_new();
+       if (rsa == NULL)
+       {
+               ERROR_MSG("Failed to instantiate OpenSSL RSA object");
+
+               return false;
+       }
+
+       BIGNUM* bn_e = OSSL::byteString2bn(params->getE());
+
+       // Check if the key was successfully generated
+       if (!RSA_generate_key_ex(rsa, params->getBitLength(), bn_e, NULL))
+       {
+               ERROR_MSG("RSA key generation failed (0x%08X)", ERR_get_error());
+               BN_free(bn_e);
+               RSA_free(rsa);
+
+               return false;
+       }
+       BN_free(bn_e);
+
+       // Create an asymmetric key-pair object to return
+       OSSLRSAKeyPair* kp = new OSSLRSAKeyPair();
+
+       ((OSSLRSAPublicKey*) kp->getPublicKey())->setFromOSSL(rsa);
+       ((OSSLRSAPrivateKey*) kp->getPrivateKey())->setFromOSSL(rsa);
+
+       *ppKeyPair = kp;
+
+       // Release the key
+       RSA_free(rsa);
+
+       return true;
+}
+
+unsigned long OSSLRSA::getMinKeySize()
+{
+#ifdef WITH_FIPS
+       // OPENSSL_RSA_FIPS_MIN_MODULUS_BITS is 1024
+       return 1024;
+#else
+       return 512;
+#endif
+}
+
+unsigned long OSSLRSA::getMaxKeySize()
+{
+       return OPENSSL_RSA_MAX_MODULUS_BITS;
+}
+
+bool OSSLRSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppKeyPair == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       ByteString dPub = ByteString::chainDeserialise(serialisedData);
+       ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+       OSSLRSAKeyPair* kp = new OSSLRSAKeyPair();
+
+       bool rv = true;
+
+       if (!((RSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
+       {
+               rv = false;
+       }
+
+       if (!((RSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+       {
+               rv = false;
+       }
+
+       if (!rv)
+       {
+               delete kp;
+
+               return false;
+       }
+
+       *ppKeyPair = kp;
+
+       return true;
+}
+
+bool OSSLRSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPublicKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLRSAPublicKey* pub = new OSSLRSAPublicKey();
+
+       if (!pub->deserialise(serialisedData))
+       {
+               delete pub;
+
+               return false;
+       }
+
+       *ppPublicKey = pub;
+
+       return true;
+}
+
+bool OSSLRSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+       // Check input
+       if ((ppPrivateKey == NULL) ||
+           (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       OSSLRSAPrivateKey* priv = new OSSLRSAPrivateKey();
+
+       if (!priv->deserialise(serialisedData))
+       {
+               delete priv;
+
+               return false;
+       }
+
+       *ppPrivateKey = priv;
+
+       return true;
+}
+
+PublicKey* OSSLRSA::newPublicKey()
+{
+       return (PublicKey*) new OSSLRSAPublicKey();
+}
+
+PrivateKey* OSSLRSA::newPrivateKey()
+{
+       return (PrivateKey*) new OSSLRSAPrivateKey();
+}
+
+AsymmetricParameters* OSSLRSA::newParameters()
+{
+       return (AsymmetricParameters*) new RSAParameters();
+}
+
+bool OSSLRSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+       // Check input parameters
+       if ((ppParams == NULL) || (serialisedData.size() == 0))
+       {
+               return false;
+       }
+
+       RSAParameters* params = new RSAParameters();
+
+       if (!params->deserialise(serialisedData))
+       {
+               delete params;
+
+               return false;
+       }
+
+       *ppParams = params;
+
+       return true;
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSA.h b/SoftHSMv2/src/lib/crypto/OSSLRSA.h
new file mode 100644 (file)
index 0000000..5b7db6d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSA.h
+
+ OpenSSL RSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLRSA_H
+#define _SOFTHSM_V2_OSSLRSA_H
+
+#include "config.h"
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include <openssl/rsa.h>
+
+class OSSLRSA : public AsymmetricAlgorithm
+{
+public:
+       // Constructor
+       OSSLRSA();
+
+       // Destructor
+       virtual ~OSSLRSA();
+
+       // Signing functions
+       virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool signUpdate(const ByteString& dataToSign);
+       virtual bool signFinal(ByteString& signature);
+
+       // Verification functions
+       virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0);
+       virtual bool verifyUpdate(const ByteString& originalData);
+       virtual bool verifyFinal(const ByteString& signature);
+
+       // Encryption functions
+       virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding);
+
+       // Decryption functions
+       virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
+
+       // Key factory
+       virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL);
+       virtual unsigned long getMinKeySize();
+       virtual unsigned long getMaxKeySize();
+       virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData);
+       virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData);
+       virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData);
+       virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData);
+       virtual PublicKey* newPublicKey();
+       virtual PrivateKey* newPrivateKey();
+       virtual AsymmetricParameters* newParameters();
+
+private:
+       HashAlgorithm* pCurrentHash;
+       HashAlgorithm* pSecondHash;
+       size_t sLen;
+};
+
+#endif // !_SOFTHSM_V2_OSSLRSA_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp b/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp
new file mode 100644 (file)
index 0000000..6465d9c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAKeyPair.cpp
+
+ OpenSSL RSA key-pair class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLRSAKeyPair.h"
+
+// Set the public key
+void OSSLRSAKeyPair::setPublicKey(OSSLRSAPublicKey& publicKey)
+{
+       pubKey = publicKey;
+}
+
+// Set the private key
+void OSSLRSAKeyPair::setPrivateKey(OSSLRSAPrivateKey& privateKey)
+{
+       privKey = privateKey;
+}
+
+// Return the public key
+PublicKey* OSSLRSAKeyPair::getPublicKey()
+{
+       return &pubKey;
+}
+
+const PublicKey* OSSLRSAKeyPair::getConstPublicKey() const
+{
+       return &pubKey;
+}
+
+// Return the private key
+PrivateKey* OSSLRSAKeyPair::getPrivateKey()
+{
+       return &privKey;
+}
+
+const PrivateKey* OSSLRSAKeyPair::getConstPrivateKey() const
+{
+       return &privKey;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h b/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h
new file mode 100644 (file)
index 0000000..546ba96
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAKeyPair.h
+
+ OpenSSL RSA key-pair class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLRSAKEYPAIR_H
+#define _SOFTHSM_V2_OSSLRSAKEYPAIR_H
+
+#include "config.h"
+#include "AsymmetricKeyPair.h"
+#include "OSSLRSAPublicKey.h"
+#include "OSSLRSAPrivateKey.h"
+
+class OSSLRSAKeyPair : public AsymmetricKeyPair
+{
+public:
+       // Set the public key
+       void setPublicKey(OSSLRSAPublicKey& publicKey);
+
+       // Set the private key
+       void setPrivateKey(OSSLRSAPrivateKey& privateKey);
+
+       // Return the public key
+       virtual PublicKey* getPublicKey();
+       virtual const PublicKey* getConstPublicKey() const;
+
+       // Return the private key
+       virtual PrivateKey* getPrivateKey();
+       virtual const PrivateKey* getConstPrivateKey() const;
+
+private:
+       // The public key
+       OSSLRSAPublicKey pubKey;
+
+       // The private key
+       OSSLRSAPrivateKey privKey;
+};
+
+#endif // !_SOFTHSM_V2_OSSLRSAKEYPAIR_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..26065cf
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAPrivateKey.cpp
+
+ OpenSSL RSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLComp.h"
+#include "OSSLRSAPrivateKey.h"
+#include "OSSLUtil.h"
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Constructors
+OSSLRSAPrivateKey::OSSLRSAPrivateKey()
+{
+       rsa = NULL;
+}
+
+OSSLRSAPrivateKey::OSSLRSAPrivateKey(const RSA* inRSA)
+{
+       rsa = NULL;
+
+       setFromOSSL(inRSA);
+}
+
+// Destructor
+OSSLRSAPrivateKey::~OSSLRSAPrivateKey()
+{
+       RSA_free(rsa);
+}
+
+// The type
+/*static*/ const char* OSSLRSAPrivateKey::type = "OpenSSL RSA Private Key";
+
+// Set from OpenSSL representation
+void OSSLRSAPrivateKey::setFromOSSL(const RSA* inRSA)
+{
+       const BIGNUM* bn_p = NULL;
+       const BIGNUM* bn_q = NULL;
+       const BIGNUM* bn_dmp1 = NULL;
+       const BIGNUM* bn_dmq1 = NULL;
+       const BIGNUM* bn_iqmp = NULL;
+       const BIGNUM* bn_n = NULL;
+       const BIGNUM* bn_e = NULL;
+       const BIGNUM* bn_d = NULL;
+
+       RSA_get0_factors(inRSA, &bn_p, &bn_q);
+       RSA_get0_crt_params(inRSA, &bn_dmp1, &bn_dmq1, &bn_iqmp);
+       RSA_get0_key(inRSA, &bn_n, &bn_e, &bn_d);
+
+       if (bn_p)
+       {
+               ByteString inP = OSSL::bn2ByteString(bn_p);
+               setP(inP);
+       }
+       if (bn_q)
+       {
+               ByteString inQ = OSSL::bn2ByteString(bn_q);
+               setQ(inQ);
+       }
+       if (bn_dmp1)
+       {
+               ByteString inDP1 = OSSL::bn2ByteString(bn_dmp1);
+               setDP1(inDP1);
+       }
+       if (bn_dmq1)
+       {
+               ByteString inDQ1 = OSSL::bn2ByteString(bn_dmq1);
+               setDQ1(inDQ1);
+       }
+       if (bn_iqmp)
+       {
+               ByteString inPQ = OSSL::bn2ByteString(bn_iqmp);
+               setPQ(inPQ);
+       }
+       if (bn_n)
+       {
+               ByteString inN = OSSL::bn2ByteString(bn_n);
+               setN(inN);
+       }
+       if (bn_e)
+       {
+               ByteString inE = OSSL::bn2ByteString(bn_e);
+               setE(inE);
+       }
+       if (bn_d)
+       {
+               ByteString inD = OSSL::bn2ByteString(bn_d);
+               setD(inD);
+       }
+}
+
+// Check if the key is of the given type
+bool OSSLRSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Setters for the RSA private key components
+void OSSLRSAPrivateKey::setP(const ByteString& inP)
+{
+       RSAPrivateKey::setP(inP);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setQ(const ByteString& inQ)
+{
+       RSAPrivateKey::setQ(inQ);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setPQ(const ByteString& inPQ)
+{
+       RSAPrivateKey::setPQ(inPQ);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setDP1(const ByteString& inDP1)
+{
+       RSAPrivateKey::setDP1(inDP1);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setDQ1(const ByteString& inDQ1)
+{
+       RSAPrivateKey::setDQ1(inDQ1);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setD(const ByteString& inD)
+{
+       RSAPrivateKey::setD(inD);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+
+// Setters for the RSA public key components
+void OSSLRSAPrivateKey::setN(const ByteString& inN)
+{
+       RSAPrivateKey::setN(inN);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPrivateKey::setE(const ByteString& inE)
+{
+       RSAPrivateKey::setE(inE);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+// Encode into PKCS#8 DER
+ByteString OSSLRSAPrivateKey::PKCS8Encode()
+{
+       ByteString der;
+       if (rsa == NULL) createOSSLKey();
+       if (rsa == NULL) return der;
+       EVP_PKEY* pkey = EVP_PKEY_new();
+       if (pkey == NULL) return der;
+       if (!EVP_PKEY_set1_RSA(pkey, rsa))
+       {
+               EVP_PKEY_free(pkey);
+               return der;
+       }
+       PKCS8_PRIV_KEY_INFO* p8inf = EVP_PKEY2PKCS8(pkey);
+       EVP_PKEY_free(pkey);
+       if (p8inf == NULL) return der;
+       int len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, NULL);
+       if (len < 0)
+       {
+               PKCS8_PRIV_KEY_INFO_free(p8inf);
+               return der;
+       }
+       der.resize(len);
+       unsigned char* priv = &der[0];
+       int len2 = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &priv);
+       PKCS8_PRIV_KEY_INFO_free(p8inf);
+       if (len2 != len) der.wipe();
+       return der;
+}
+
+// Decode from PKCS#8 BER
+bool OSSLRSAPrivateKey::PKCS8Decode(const ByteString& ber)
+{
+       int len = ber.size();
+       if (len <= 0) return false;
+       const unsigned char* priv = ber.const_byte_str();
+       PKCS8_PRIV_KEY_INFO* p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &priv, len);
+       if (p8 == NULL) return false;
+       EVP_PKEY* pkey = EVP_PKCS82PKEY(p8);
+       PKCS8_PRIV_KEY_INFO_free(p8);
+       if (pkey == NULL) return false;
+       RSA* key = EVP_PKEY_get1_RSA(pkey);
+       EVP_PKEY_free(pkey);
+       if (key == NULL) return false;
+       setFromOSSL(key);
+       RSA_free(key);
+       return true;
+}
+
+// Retrieve the OpenSSL representation of the key
+RSA* OSSLRSAPrivateKey::getOSSLKey()
+{
+       if (rsa == NULL) createOSSLKey();
+
+       return rsa;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLRSAPrivateKey::createOSSLKey()
+{
+       if (rsa != NULL) return;
+
+       rsa = RSA_new();
+       if (rsa == NULL)
+       {
+               ERROR_MSG("Could not create RSA object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               RSA_set_method(rsa, FIPS_rsa_pkcs1_ssleay());
+       else
+               RSA_set_method(rsa, RSA_PKCS1_SSLeay());
+#else
+       RSA_set_method(rsa, RSA_PKCS1_SSLeay());
+#endif
+
+#else
+       RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
+#endif
+
+       BIGNUM* bn_p = OSSL::byteString2bn(p);
+       BIGNUM* bn_q = OSSL::byteString2bn(q);
+       BIGNUM* bn_dmp1 = OSSL::byteString2bn(dp1);
+       BIGNUM* bn_dmq1 = OSSL::byteString2bn(dq1);
+       BIGNUM* bn_iqmp = OSSL::byteString2bn(pq);
+       BIGNUM* bn_n = OSSL::byteString2bn(n);
+       BIGNUM* bn_e = OSSL::byteString2bn(e);
+       BIGNUM* bn_d = OSSL::byteString2bn(d);
+
+       RSA_set0_factors(rsa, bn_p, bn_q);
+       RSA_set0_crt_params(rsa, bn_dmp1, bn_dmq1, bn_iqmp);
+       RSA_set0_key(rsa, bn_n, bn_e, bn_d);
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h
new file mode 100644 (file)
index 0000000..bb876d5
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAPrivateKey.h
+
+ OpenSSL RSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLRSAPRIVATEKEY_H
+#define _SOFTHSM_V2_OSSLRSAPRIVATEKEY_H
+
+#include "config.h"
+#include "RSAPrivateKey.h"
+#include <openssl/rsa.h>
+
+class OSSLRSAPrivateKey : public RSAPrivateKey
+{
+public:
+       // Constructors
+       OSSLRSAPrivateKey();
+
+       OSSLRSAPrivateKey(const RSA* inRSA);
+
+       // Destructor
+       virtual ~OSSLRSAPrivateKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the RSA private key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setPQ(const ByteString& inPQ);
+       virtual void setDP1(const ByteString& inDP1);
+       virtual void setDQ1(const ByteString& inDQ1);
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode();
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const RSA* inRSA);
+
+       // Retrieve the OpenSSL representation of the key
+       RSA* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       RSA* rsa;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLRSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..2a6893b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAPublicKey.cpp
+
+ OpenSSL RSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLComp.h"
+#include "OSSLRSAPublicKey.h"
+#include "OSSLUtil.h"
+#include <string.h>
+#include <openssl/bn.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+
+// Constructors
+OSSLRSAPublicKey::OSSLRSAPublicKey()
+{
+       rsa = NULL;
+}
+
+OSSLRSAPublicKey::OSSLRSAPublicKey(const RSA* inRSA)
+{
+       rsa = NULL;
+
+       setFromOSSL(inRSA);
+}
+
+// Destructor
+OSSLRSAPublicKey::~OSSLRSAPublicKey()
+{
+       RSA_free(rsa);
+}
+
+// The type
+/*static*/ const char* OSSLRSAPublicKey::type = "OpenSSL RSA Public Key";
+
+// Check if the key is of the given type
+bool OSSLRSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Set from OpenSSL representation
+void OSSLRSAPublicKey::setFromOSSL(const RSA* inRSA)
+{
+       const BIGNUM* bn_n = NULL;
+       const BIGNUM* bn_e = NULL;
+
+       RSA_get0_key(inRSA, &bn_n, &bn_e, NULL);
+
+       if (bn_n)
+       {
+               ByteString inN = OSSL::bn2ByteString(bn_n);
+               setN(inN);
+       }
+       if (bn_e)
+       {
+               ByteString inE = OSSL::bn2ByteString(bn_e);
+               setE(inE);
+       }
+}
+
+// Setters for the RSA public key components
+void OSSLRSAPublicKey::setN(const ByteString& inN)
+{
+       RSAPublicKey::setN(inN);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+void OSSLRSAPublicKey::setE(const ByteString& inE)
+{
+       RSAPublicKey::setE(inE);
+
+       if (rsa)
+       {
+               RSA_free(rsa);
+               rsa = NULL;
+       }
+}
+
+// Retrieve the OpenSSL representation of the key
+RSA* OSSLRSAPublicKey::getOSSLKey()
+{
+       if (rsa == NULL) createOSSLKey();
+
+       return rsa;
+}
+
+// Create the OpenSSL representation of the key
+void OSSLRSAPublicKey::createOSSLKey()
+{
+       if (rsa != NULL) return;
+
+       rsa = RSA_new();
+       if (rsa == NULL)
+       {
+               ERROR_MSG("Could not create RSA object");
+               return;
+       }
+
+       // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+       if (FIPS_mode())
+               RSA_set_method(rsa, FIPS_rsa_pkcs1_ssleay());
+       else
+               RSA_set_method(rsa, RSA_PKCS1_SSLeay());
+#else
+       RSA_set_method(rsa, RSA_PKCS1_SSLeay());
+#endif
+
+#else
+       RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
+#endif
+
+       BIGNUM* bn_n = OSSL::byteString2bn(n);
+       BIGNUM* bn_e = OSSL::byteString2bn(e);
+
+       RSA_set0_key(rsa, bn_n, bn_e, NULL);
+}
diff --git a/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h b/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h
new file mode 100644 (file)
index 0000000..98f99f2
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLRSAPublicKey.h
+
+ OpenSSL RSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLRSAPUBLICKEY_H
+#define _SOFTHSM_V2_OSSLRSAPUBLICKEY_H
+
+#include "config.h"
+#include "RSAPublicKey.h"
+#include <openssl/rsa.h>
+
+class OSSLRSAPublicKey : public RSAPublicKey
+{
+public:
+       // Constructors
+       OSSLRSAPublicKey();
+
+       OSSLRSAPublicKey(const RSA* inRSA);
+
+       // Destructor
+       virtual ~OSSLRSAPublicKey();
+
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Set from OpenSSL representation
+       virtual void setFromOSSL(const RSA* inRSA);
+
+       // Retrieve the OpenSSL representation of the key
+       RSA* getOSSLKey();
+
+private:
+       // The internal OpenSSL representation
+       RSA* rsa;
+
+       // Create the OpenSSL representation of the key
+       void createOSSLKey();
+};
+
+#endif // !_SOFTHSM_V2_OSSLRSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp b/SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp
new file mode 100644 (file)
index 0000000..fcee390
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA1.h
+
+ OpenSSL SHA1 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLSHA1.h"
+#include <openssl/evp.h>
+
+int OSSLSHA1::getHashSize()
+{
+       return 20;
+}
+
+const EVP_MD* OSSLSHA1::getEVPHash() const
+{
+       return EVP_sha1();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA1.h b/SoftHSMv2/src/lib/crypto/OSSLSHA1.h
new file mode 100644 (file)
index 0000000..011803b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA1.h
+
+ OpenSSL SHA1 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLSHA1_H
+#define _SOFTHSM_V2_OSSLSHA1_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLSHA1 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLSHA1_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp b/SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp
new file mode 100644 (file)
index 0000000..7dacf56
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA224.h
+
+ OpenSSL SHA224 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLSHA224.h"
+#include <openssl/evp.h>
+
+int OSSLSHA224::getHashSize()
+{
+       return 28;
+}
+
+const EVP_MD* OSSLSHA224::getEVPHash() const
+{
+       return EVP_sha224();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA224.h b/SoftHSMv2/src/lib/crypto/OSSLSHA224.h
new file mode 100644 (file)
index 0000000..f83ddf7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA224.h
+
+ OpenSSL SHA224 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLSHA224_H
+#define _SOFTHSM_V2_OSSLSHA224_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLSHA224 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLSHA224_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp b/SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp
new file mode 100644 (file)
index 0000000..d8b57b0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA256.h
+
+ OpenSSL SHA256 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLSHA256.h"
+#include <openssl/evp.h>
+
+int OSSLSHA256::getHashSize()
+{
+       return 32;
+}
+
+const EVP_MD* OSSLSHA256::getEVPHash() const
+{
+       return EVP_sha256();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA256.h b/SoftHSMv2/src/lib/crypto/OSSLSHA256.h
new file mode 100644 (file)
index 0000000..1f22386
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA256.h
+
+ OpenSSL SHA256 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLSHA256_H
+#define _SOFTHSM_V2_OSSLSHA256_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLSHA256 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLSHA256_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp b/SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp
new file mode 100644 (file)
index 0000000..01b6fce
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA384.h
+
+ OpenSSL SHA384 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLSHA384.h"
+#include <openssl/evp.h>
+
+int OSSLSHA384::getHashSize()
+{
+       return 48;
+}
+
+const EVP_MD* OSSLSHA384::getEVPHash() const
+{
+       return EVP_sha384();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA384.h b/SoftHSMv2/src/lib/crypto/OSSLSHA384.h
new file mode 100644 (file)
index 0000000..9b93724
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA384.h
+
+ OpenSSL SHA384 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLSHA384_H
+#define _SOFTHSM_V2_OSSLSHA384_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLSHA384 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLSHA384_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp b/SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp
new file mode 100644 (file)
index 0000000..4533354
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA512.h
+
+ OpenSSL SHA512 implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSSLSHA512.h"
+#include <openssl/evp.h>
+
+int OSSLSHA512::getHashSize()
+{
+       return 64;
+}
+
+const EVP_MD* OSSLSHA512::getEVPHash() const
+{
+       return EVP_sha512();
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLSHA512.h b/SoftHSMv2/src/lib/crypto/OSSLSHA512.h
new file mode 100644 (file)
index 0000000..cb266d8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLSHA512.h
+
+ OpenSSL SHA512 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLSHA512_H
+#define _SOFTHSM_V2_OSSLSHA512_H
+
+#include "config.h"
+#include "OSSLEVPHashAlgorithm.h"
+#include <openssl/evp.h>
+
+class OSSLSHA512 : public OSSLEVPHashAlgorithm
+{
+       virtual int getHashSize();
+protected:
+       virtual const EVP_MD* getEVPHash() const;
+};
+
+#endif // !_SOFTHSM_V2_OSSLSHA512_H
+
diff --git a/SoftHSMv2/src/lib/crypto/OSSLUtil.cpp b/SoftHSMv2/src/lib/crypto/OSSLUtil.cpp
new file mode 100644 (file)
index 0000000..981bb98
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLUtil.h
+
+ OpenSSL convenience functions
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLUtil.h"
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+
+// Convert an OpenSSL BIGNUM to a ByteString
+ByteString OSSL::bn2ByteString(const BIGNUM* bn)
+{
+       ByteString rv;
+
+       if (bn != NULL)
+       {
+               rv.resize(BN_num_bytes(bn));
+               BN_bn2bin(bn, &rv[0]);
+       }
+
+       return rv;
+}
+
+// Convert a ByteString to an OpenSSL BIGNUM
+BIGNUM* OSSL::byteString2bn(const ByteString& byteString)
+{
+       if (byteString.size() == 0) return NULL;
+
+       return BN_bin2bn(byteString.const_byte_str(), byteString.size(), NULL);
+}
+
+#ifdef WITH_ECC
+// Convert an OpenSSL EC GROUP to a ByteString
+ByteString OSSL::grp2ByteString(const EC_GROUP* grp)
+{
+       ByteString rv;
+
+       if (grp != NULL)
+       {
+               rv.resize(i2d_ECPKParameters(grp, NULL));
+               unsigned char *p = &rv[0];
+               i2d_ECPKParameters(grp, &p);
+       }
+
+       return rv;
+}
+
+// Convert a ByteString to an OpenSSL EC GROUP
+EC_GROUP* OSSL::byteString2grp(const ByteString& byteString)
+{
+       const unsigned char *p = byteString.const_byte_str();
+       return d2i_ECPKParameters(NULL, &p, byteString.size());
+}
+
+// POINT_CONVERSION_UNCOMPRESSED               0x04
+
+// Convert an OpenSSL EC POINT in the given EC GROUP to a ByteString
+ByteString OSSL::pt2ByteString(const EC_POINT* pt, const EC_GROUP* grp)
+{
+       ByteString rv;
+
+       if (pt != NULL && grp != NULL)
+       {
+               size_t len = EC_POINT_point2oct(grp, pt, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
+               // Definite, short
+               if (len <= 0x7f)
+               {
+                       rv.resize(2 + len);
+                       rv[0] = V_ASN1_OCTET_STRING;
+                       rv[1] = len & 0x7f;
+                       EC_POINT_point2oct(grp, pt, POINT_CONVERSION_UNCOMPRESSED, &rv[2], len, NULL);
+               }
+               // Definite, long
+               else
+               {
+                       // Get the number of length octets
+                       ByteString length(len);
+                       unsigned int counter = 0;
+                       while (length[counter] == 0 && counter < (length.size()-1)) counter++;
+                       ByteString lengthOctets(&length[counter], length.size() - counter);
+
+                       rv.resize(len + 2 + lengthOctets.size());
+                       rv[0] = V_ASN1_OCTET_STRING;
+                       rv[1] = 0x80 | lengthOctets.size();
+                       memcpy(&rv[2], &lengthOctets[0], lengthOctets.size());
+                       EC_POINT_point2oct(grp, pt, POINT_CONVERSION_UNCOMPRESSED, &rv[2 + lengthOctets.size()], len, NULL);
+               }
+       }
+
+       return rv;
+}
+
+// Convert a ByteString to an OpenSSL EC POINT in the given EC GROUP
+EC_POINT* OSSL::byteString2pt(const ByteString& byteString, const EC_GROUP* grp)
+{
+       size_t len = byteString.size();
+       size_t controlOctets = 2;
+       if (len < controlOctets)
+       {
+               ERROR_MSG("Undersized EC point");
+
+               return NULL;
+       }
+
+       ByteString repr = byteString;
+
+       if (repr[0] != V_ASN1_OCTET_STRING)
+       {
+               ERROR_MSG("EC point tag is not OCTET STRING");
+
+               return NULL;
+       }
+
+       // Definite, short
+       if (repr[1] < 0x80)
+       {
+               if (repr[1] != (len - controlOctets))
+               {
+                       if (repr[1] < (len - controlOctets))
+                       {
+                               ERROR_MSG("Underrun EC point");
+                       }
+                       else
+                       {
+                               ERROR_MSG("Overrun EC point");
+                       }
+
+                       return NULL;
+               }
+       }
+       // Definite, long
+       else
+       {
+               size_t lengthOctets = repr[1] & 0x7f;
+               controlOctets += lengthOctets;
+
+               if (controlOctets >= repr.size())
+               {
+                       ERROR_MSG("Undersized EC point");
+
+                       return NULL;
+               }
+
+               ByteString length(&repr[2], lengthOctets);
+
+               if (length.long_val() != (len - controlOctets))
+               {
+                       if (length.long_val() < (len - controlOctets))
+                       {
+                               ERROR_MSG("Underrun EC point");
+                       }
+                       else
+                       {
+                               ERROR_MSG("Overrun EC point");
+                       }
+
+                       return NULL;
+               }
+       }
+
+       EC_POINT* pt = EC_POINT_new(grp);
+       if (!EC_POINT_oct2point(grp, pt, &repr[controlOctets], len - controlOctets, NULL))
+       {
+               ERROR_MSG("EC_POINT_oct2point failed: %s", ERR_error_string(ERR_get_error(), NULL));
+               EC_POINT_free(pt);
+               return NULL;
+       }
+       return pt;
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/OSSLUtil.h b/SoftHSMv2/src/lib/crypto/OSSLUtil.h
new file mode 100644 (file)
index 0000000..f353cc6
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLUtil.h
+
+ OpenSSL convenience functions
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSSLUTIL_H
+#define _SOFTHSM_V2_OSSLUTIL_H
+
+#include "config.h"
+#include "ByteString.h"
+#include <openssl/bn.h>
+#ifdef WITH_ECC
+#include <openssl/ec.h>
+#endif
+
+namespace OSSL
+{
+       // Convert an OpenSSL BIGNUM to a ByteString
+       ByteString bn2ByteString(const BIGNUM* bn);
+
+       // Convert a ByteString to an OpenSSL BIGNUM
+       BIGNUM* byteString2bn(const ByteString& byteString);
+
+#ifdef WITH_ECC
+       // Convert an OpenSSL EC GROUP to a ByteString
+       ByteString grp2ByteString(const EC_GROUP* grp);
+
+       // Convert a ByteString to an OpenSSL EC GROUP
+       EC_GROUP* byteString2grp(const ByteString& byteString);
+
+       // Convert an OpenSSL EC POINT in the given EC GROUP to a ByteString
+       ByteString pt2ByteString(const EC_POINT* pt, const EC_GROUP* grp);
+
+       // Convert a ByteString to an OpenSSL EC POINT in the given EC GROUP
+       EC_POINT* byteString2pt(const ByteString& byteString, const EC_GROUP* grp);
+#endif
+}
+
+#endif // !_SOFTHSM_V2_OSSLUTIL_H
+
diff --git a/SoftHSMv2/src/lib/crypto/PrivateKey.h b/SoftHSMv2/src/lib/crypto/PrivateKey.h
new file mode 100644 (file)
index 0000000..cb14539
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ PrivateKey.h
+
+ Base class for private key classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_PRIVATEKEY_H
+#define _SOFTHSM_V2_PRIVATEKEY_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+#include <string>
+
+class PrivateKey : public Serialisable
+{
+public:
+       // Base constructors
+       PrivateKey() { }
+
+       PrivateKey(const PrivateKey& in);
+
+       // Destructor
+       virtual ~PrivateKey() { }
+
+       // Check if the private key is of the given type
+       virtual bool isOfType(const char* inType) = 0;
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const = 0;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const = 0;
+
+       // Serialisation
+       virtual ByteString serialise() const = 0;
+
+       // Encode into PKCS#8 DER
+       virtual ByteString PKCS8Encode() = 0;
+
+       // Decode from PKCS#8 BER
+       virtual bool PKCS8Decode(const ByteString& ber) = 0;
+};
+
+#endif // !_SOFTHSM_V2_PRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/PublicKey.h b/SoftHSMv2/src/lib/crypto/PublicKey.h
new file mode 100644 (file)
index 0000000..2207e8d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ PublicKey.h
+
+ Base class for public key classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_PUBLICKEY_H
+#define _SOFTHSM_V2_PUBLICKEY_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+
+class PublicKey : public Serialisable
+{
+public:
+       // Base constructors
+       PublicKey() { }
+
+       PublicKey(const PublicKey& /*in*/) { }
+
+       // Destructor
+       virtual ~PublicKey() { }
+
+       // Check if it is of the given type
+       virtual bool isOfType(const char* inType) = 0;
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const = 0;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const = 0;
+
+       // Serialisation
+       virtual ByteString serialise() const = 0;
+};
+
+#endif // !_SOFTHSM_V2_PUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/RNG.h b/SoftHSMv2/src/lib/crypto/RNG.h
new file mode 100644 (file)
index 0000000..ea0548f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RNG.h
+
+ Base class for random number generator classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RNG_H
+#define _SOFTHSM_V2_RNG_H
+
+#include "config.h"
+#include "ByteString.h"
+
+struct RNGImpl
+{
+       enum Type
+       {
+               Unknown,
+               Default
+       };
+};
+
+class RNG
+{
+public:
+       // Base constructor
+       RNG() { }
+
+       // Destructor
+       virtual ~RNG() { }
+
+       // Generate random data
+       virtual bool generateRandom(ByteString& data, const size_t len) = 0;
+
+       // Seed the random pool
+       virtual void seed(ByteString& seedData) = 0;
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_RNG_H
+
diff --git a/SoftHSMv2/src/lib/crypto/RSAParameters.cpp b/SoftHSMv2/src/lib/crypto/RSAParameters.cpp
new file mode 100644 (file)
index 0000000..26ba7a7
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSAParameters.h
+
+ RSA parameters (only used for key generation)
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "RSAParameters.h"
+#include <string.h>
+
+// The type
+/*static*/ const char* RSAParameters::type = "Generic RSA parameters";
+
+// Set the public exponent
+void RSAParameters::setE(const ByteString& inE)
+{
+       e = inE;
+}
+
+// Set the bit length
+void RSAParameters::setBitLength(const size_t inBitLen)
+{
+       bitLen = inBitLen;
+}
+
+// Get the public exponent
+const ByteString& RSAParameters::getE() const
+{
+       return e;
+}
+
+// Get the bit length
+size_t RSAParameters::getBitLength() const
+{
+       return bitLen;
+}
+
+// Are the parameters of the given type?
+bool RSAParameters::areOfType(const char* inType)
+{
+       return (strcmp(type, inType) == 0);
+}
+
+// Serialisation
+ByteString RSAParameters::serialise() const
+{
+       ByteString len(bitLen);
+
+       return e.serialise() + len.serialise();
+}
+
+bool RSAParameters::deserialise(ByteString& serialised)
+{
+       ByteString dE = ByteString::chainDeserialise(serialised);
+       ByteString dLen = ByteString::chainDeserialise(serialised);
+
+       if ((dE.size() == 0) ||
+           (dLen.size() == 0))
+        {
+               return false;
+       }
+
+       setE(dE);
+       setBitLength(dLen.long_val());
+
+        return true;
+}
diff --git a/SoftHSMv2/src/lib/crypto/RSAParameters.h b/SoftHSMv2/src/lib/crypto/RSAParameters.h
new file mode 100644 (file)
index 0000000..c8e748e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSAParameters.h
+
+ RSA parameters (only used for key generation)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RSAPARAMETERS_H
+#define _SOFTHSM_V2_RSAPARAMETERS_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "AsymmetricParameters.h"
+
+class RSAParameters : public AsymmetricParameters
+{
+public:
+       // Base constructor
+       RSAParameters() : bitLen(0) { }
+
+       // The type
+       static const char* type;
+
+       // Set the public exponent
+       void setE(const ByteString& inE);
+
+       // Set the bit length
+       void setBitLength(const size_t inBitLen);
+
+       // Get the public exponent
+       const ByteString& getE() const;
+
+       // Get the bit length
+       size_t getBitLength() const;
+
+       // Are the parameters of the given type?
+       virtual bool areOfType(const char* inType);
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+private:
+       ByteString e;
+       size_t bitLen;
+};
+
+#endif // !_SOFTHSM_V2_RSAPARAMETERS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp b/SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp
new file mode 100644 (file)
index 0000000..7b3d43d
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSAPrivateKey.cpp
+
+ RSA private key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "RSAPrivateKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* RSAPrivateKey::type = "Abstract RSA private key";
+
+// Check if the key is of the given type
+bool RSAPrivateKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long RSAPrivateKey::getBitLength() const
+{
+       return getN().bits();
+}
+
+// Get the output length
+unsigned long RSAPrivateKey::getOutputLength() const
+{
+       // Also handle odd number of bits (bits % 8 != 0)
+       return (getBitLength() + 7) / 8;
+}
+
+// Setters for the RSA private key components
+void RSAPrivateKey::setP(const ByteString& inP)
+{
+       p = inP;
+}
+
+void RSAPrivateKey::setQ(const ByteString& inQ)
+{
+       q = inQ;
+}
+
+void RSAPrivateKey::setPQ(const ByteString& inPQ)
+{
+       pq = inPQ;
+}
+
+void RSAPrivateKey::setDP1(const ByteString& inDP1)
+{
+       dp1 = inDP1;
+}
+
+void RSAPrivateKey::setDQ1(const ByteString& inDQ1)
+{
+       dq1 = inDQ1;
+}
+
+void RSAPrivateKey::setD(const ByteString& inD)
+{
+       d = inD;
+}
+
+// Setters for the RSA public key components
+void RSAPrivateKey::setN(const ByteString& inN)
+{
+       n = inN;
+}
+
+void RSAPrivateKey::setE(const ByteString& inE)
+{
+       e = inE;
+}
+
+// Getters for the RSA private key components
+const ByteString& RSAPrivateKey::getP() const
+{
+       return p;
+}
+
+const ByteString& RSAPrivateKey::getQ() const
+{
+       return q;
+}
+
+const ByteString& RSAPrivateKey::getPQ() const
+{
+       return pq;
+}
+
+const ByteString& RSAPrivateKey::getDP1() const
+{
+       return dp1;
+}
+
+const ByteString& RSAPrivateKey::getDQ1() const
+{
+       return dq1;
+}
+
+const ByteString& RSAPrivateKey::getD() const
+{
+       return d;
+}
+
+// Getters for the RSA public key components
+const ByteString& RSAPrivateKey::getN() const
+{
+       return n;
+}
+
+const ByteString& RSAPrivateKey::getE() const
+{
+       return e;
+}
+
+// Serialisation
+ByteString RSAPrivateKey::serialise() const
+{
+       return p.serialise() +
+              q.serialise() +
+              pq.serialise() +
+              dp1.serialise() +
+              dq1.serialise() +
+              d.serialise() +
+              n.serialise() +
+              e.serialise();
+}
+
+bool RSAPrivateKey::deserialise(ByteString& serialised)
+{
+       ByteString dP = ByteString::chainDeserialise(serialised);
+       ByteString dQ = ByteString::chainDeserialise(serialised);
+       ByteString dPQ = ByteString::chainDeserialise(serialised);
+       ByteString dDP1 = ByteString::chainDeserialise(serialised);
+       ByteString dDQ1 = ByteString::chainDeserialise(serialised);
+       ByteString dD = ByteString::chainDeserialise(serialised);
+       ByteString dN = ByteString::chainDeserialise(serialised);
+       ByteString dE = ByteString::chainDeserialise(serialised);
+
+       if ((dD.size() == 0) ||
+           (dN.size() == 0) ||
+           (dE.size() == 0))
+       {
+               return false;
+       }
+
+       setP(dP);
+       setQ(dQ);
+       setPQ(dPQ);
+       setDP1(dDP1);
+       setDQ1(dDQ1);
+       setD(dD);
+       setN(dN);
+       setE(dE);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/RSAPrivateKey.h b/SoftHSMv2/src/lib/crypto/RSAPrivateKey.h
new file mode 100644 (file)
index 0000000..3c40c3c
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ RSAPrivateKey.h
+
+ RSA private key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RSAPRIVATEKEY_H
+#define _SOFTHSM_V2_RSAPRIVATEKEY_H
+
+#include "config.h"
+#include "PrivateKey.h"
+
+class RSAPrivateKey : public PrivateKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the RSA private key components
+       virtual void setP(const ByteString& inP);
+       virtual void setQ(const ByteString& inQ);
+       virtual void setPQ(const ByteString& inPQ);
+       virtual void setDP1(const ByteString& inDP1);
+       virtual void setDQ1(const ByteString& inDQ1);
+       virtual void setD(const ByteString& inD);
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Getters for the RSA private key components
+       virtual const ByteString& getP() const;
+       virtual const ByteString& getQ() const;
+       virtual const ByteString& getPQ() const;
+       virtual const ByteString& getDP1() const;
+       virtual const ByteString& getDQ1() const;
+       virtual const ByteString& getD() const;
+
+       // Getters for the RSA public key components
+       virtual const ByteString& getN() const;
+       virtual const ByteString& getE() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Private components
+       ByteString p,q,pq,dp1,dq1,d;
+
+       // Public components
+       ByteString n,e;
+};
+
+#endif // !_SOFTHSM_V2_RSAPRIVATEKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp b/SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp
new file mode 100644 (file)
index 0000000..e0e05cd
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSAPublicKey.cpp
+
+ RSA public key class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "RSAPublicKey.h"
+#include <string.h>
+
+// Set the type
+/*static*/ const char* RSAPublicKey::type = "Abstract RSA public key";
+
+// Check if the key is of the given type
+bool RSAPublicKey::isOfType(const char* inType)
+{
+       return !strcmp(type, inType);
+}
+
+// Get the bit length
+unsigned long RSAPublicKey::getBitLength() const
+{
+       return getN().bits();
+}
+
+// Get the output length
+unsigned long RSAPublicKey::getOutputLength() const
+{
+       // Also handle odd number of bits (bits % 8 != 0)
+       return (getBitLength() + 7) / 8;
+}
+
+// Setters for the RSA public key components
+void RSAPublicKey::setN(const ByteString& inN)
+{
+       n = inN;
+}
+
+void RSAPublicKey::setE(const ByteString& inE)
+{
+       e = inE;
+}
+
+// Getters for the RSA public key components
+const ByteString& RSAPublicKey::getN() const
+{
+       return n;
+}
+
+const ByteString& RSAPublicKey::getE() const
+{
+       return e;
+}
+
+// Serialisation
+ByteString RSAPublicKey::serialise() const
+{
+       return n.serialise() +
+              e.serialise();
+}
+
+bool RSAPublicKey::deserialise(ByteString& serialised)
+{
+       ByteString dN = ByteString::chainDeserialise(serialised);
+       ByteString dE = ByteString::chainDeserialise(serialised);
+
+       if ((dN.size() == 0) ||
+           (dE.size() == 0))
+       {
+               return false;
+       }
+
+       setN(dN);
+       setE(dE);
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/RSAPublicKey.h b/SoftHSMv2/src/lib/crypto/RSAPublicKey.h
new file mode 100644 (file)
index 0000000..9256966
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ RSAPublicKey.h
+
+ RSA public key class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RSAPUBLICKEY_H
+#define _SOFTHSM_V2_RSAPUBLICKEY_H
+
+#include "config.h"
+#include "PublicKey.h"
+
+class RSAPublicKey : public PublicKey
+{
+public:
+       // The type
+       static const char* type;
+
+       // Check if the key is of the given type
+       virtual bool isOfType(const char* inType);
+
+       // Get the bit length
+       virtual unsigned long getBitLength() const;
+
+       // Get the output length
+       virtual unsigned long getOutputLength() const;
+
+       // Setters for the RSA public key components
+       virtual void setN(const ByteString& inN);
+       virtual void setE(const ByteString& inE);
+
+       // Getters for the RSA public key components
+       virtual const ByteString& getN() const;
+       virtual const ByteString& getE() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+       virtual bool deserialise(ByteString& serialised);
+
+protected:
+       // Public components
+       ByteString n,e;
+};
+
+#endif // !_SOFTHSM_V2_RSAPUBLICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp b/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp
new file mode 100644 (file)
index 0000000..1db8f50
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricAlgorithm.cpp
+
+ Base class for symmetric algorithm classes
+ *****************************************************************************/
+
+#include "SymmetricAlgorithm.h"
+#include <algorithm>
+#include <string.h>
+
+SymmetricAlgorithm::SymmetricAlgorithm()
+{
+       currentKey = NULL;
+       currentCipherMode = SymMode::Unknown;
+       currentPaddingMode = true;
+       currentCounterBits = 0;
+       currentTagBytes = 0;
+       currentOperation = NONE;
+       currentBufferSize = 0;
+}
+
+bool SymmetricAlgorithm::encryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode::CBC */, const ByteString& /*IV = ByteString() */, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& /*aad = ByteString()*/, size_t tagBytes /* = 0 */)
+{
+       if ((key == NULL) || (currentOperation != NONE))
+       {
+               return false;
+       }
+
+       currentKey = key;
+       currentCipherMode = mode;
+       currentPaddingMode = padding;
+       currentCounterBits = counterBits;
+       currentTagBytes = tagBytes;
+       currentOperation = ENCRYPT;
+       currentBufferSize = 0;
+
+       return true;
+}
+
+bool SymmetricAlgorithm::encryptUpdate(const ByteString& data, ByteString& /*encryptedData*/)
+{
+       if (currentOperation != ENCRYPT)
+       {
+               return false;
+       }
+
+       currentBufferSize += data.size();
+
+       return true;
+}
+
+bool SymmetricAlgorithm::encryptFinal(ByteString& /*encryptedData*/)
+{
+       if (currentOperation != ENCRYPT)
+       {
+               return false;
+       }
+
+       currentKey = NULL;
+       currentCipherMode = SymMode::Unknown;
+       currentPaddingMode = true;
+       currentCounterBits = 0;
+       currentTagBytes = 0;
+       currentOperation = NONE;
+       currentBufferSize = 0;
+
+       return true;
+}
+
+bool SymmetricAlgorithm::decryptInit(const SymmetricKey* key, const SymMode::Type mode /* = SymMode::CBC */, const ByteString& /*IV = ByteString() */, bool padding /* = true */, size_t counterBits /* = 0 */, const ByteString& /*aad = ByteString()*/, size_t tagBytes /* = 0 */)
+{
+       if ((key == NULL) || (currentOperation != NONE))
+       {
+               return false;
+       }
+
+       currentKey = key;
+       currentCipherMode = mode;
+       currentPaddingMode = padding;
+       currentCounterBits = counterBits;
+       currentTagBytes = tagBytes;
+       currentOperation = DECRYPT;
+       currentBufferSize = 0;
+       currentAEADBuffer.wipe();
+
+       return true;
+}
+
+
+bool SymmetricAlgorithm::decryptUpdate(const ByteString& encryptedData, ByteString& /*data*/)
+{
+       if (currentOperation != DECRYPT)
+       {
+               return false;
+       }
+
+       currentBufferSize += encryptedData.size();
+       currentAEADBuffer += encryptedData;
+
+       return true;
+}
+
+bool SymmetricAlgorithm::decryptFinal(ByteString& /*data*/)
+{
+       if (currentOperation != DECRYPT)
+       {
+               return false;
+       }
+
+       currentKey = NULL;
+       currentCipherMode = SymMode::Unknown;
+       currentPaddingMode = true;
+       currentCounterBits = 0;
+       currentTagBytes = 0;
+       currentOperation = NONE;
+       currentBufferSize = 0;
+       currentAEADBuffer.wipe();
+
+       return true;
+}
+
+// Key factory
+void SymmetricAlgorithm::recycleKey(SymmetricKey* toRecycle)
+{
+       delete toRecycle;
+}
+
+bool SymmetricAlgorithm::generateKey(SymmetricKey& key, RNG* rng /* = NULL */)
+{
+       if (rng == NULL)
+       {
+               return false;
+       }
+
+       if (key.getBitLen() == 0)
+       {
+               return false;
+       }
+
+       ByteString keyBits;
+
+       if (!rng->generateRandom(keyBits, key.getBitLen()/8))
+       {
+               return false;
+       }
+
+       return key.setKeyBits(keyBits);
+}
+
+bool SymmetricAlgorithm::reconstructKey(SymmetricKey& key, const ByteString& serialisedData)
+{
+       return key.setKeyBits(serialisedData);
+}
+
+SymMode::Type SymmetricAlgorithm::getCipherMode()
+{
+       return currentCipherMode;
+}
+
+bool SymmetricAlgorithm::getPaddingMode()
+{
+       return currentPaddingMode;
+}
+
+unsigned long SymmetricAlgorithm::getBufferSize()
+{
+       return currentBufferSize;
+}
+
+size_t SymmetricAlgorithm::getTagBytes()
+{
+       return currentTagBytes;
+}
+
+bool SymmetricAlgorithm::isStreamCipher()
+{
+       switch (currentCipherMode)
+       {
+               case SymMode::CFB:
+               case SymMode::CTR:
+               case SymMode::GCM:
+               case SymMode::OFB:
+                       return true;
+               default:
+                       break;
+       }
+
+       return false;
+}
+
+bool SymmetricAlgorithm::isBlockCipher()
+{
+       switch (currentCipherMode)
+       {
+               case SymMode::CBC:
+               case SymMode::ECB:
+                       return true;
+               default:
+                       break;
+       }
+
+       return false;
+}
diff --git a/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h b/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h
new file mode 100644 (file)
index 0000000..7e060c4
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricAlgorithm.h
+
+ Base class for symmetric algorithm classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SYMMETRICALGORITHM_H
+#define _SOFTHSM_V2_SYMMETRICALGORITHM_H
+
+#include <string>
+#include "config.h"
+#include "SymmetricKey.h"
+#include "RNG.h"
+
+struct SymAlgo
+{
+       enum Type
+       {
+               Unknown,
+               AES,
+               DES,
+               DES3
+       };
+};
+
+struct SymMode
+{
+       enum Type
+       {
+               Unknown,
+               CBC,
+               CFB,
+               CTR,
+               ECB,
+               GCM,
+               OFB
+       };
+};
+
+struct SymWrap
+{
+       enum Type
+       {
+               Unknown,
+               AES_KEYWRAP,
+               AES_KEYWRAP_PAD
+       };
+};
+
+class SymmetricAlgorithm
+{
+public:
+       // Base constructors
+       SymmetricAlgorithm();
+
+       // Destructor
+       virtual ~SymmetricAlgorithm() { }
+
+       // Encryption functions
+       virtual bool encryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool encryptUpdate(const ByteString& data, ByteString& encryptedData);
+       virtual bool encryptFinal(ByteString& encryptedData);
+
+       // Decryption functions
+       virtual bool decryptInit(const SymmetricKey* key, const SymMode::Type mode = SymMode::CBC, const ByteString& IV = ByteString(), bool padding = true, size_t counterBits = 0, const ByteString& aad = ByteString(), size_t tagBytes = 0);
+       virtual bool decryptUpdate(const ByteString& encryptedData, ByteString& data);
+       virtual bool decryptFinal(ByteString& data);
+
+       // Wrap/Unwrap keys
+       virtual bool wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out) = 0;
+
+       virtual bool unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out) = 0;
+
+       // Key factory
+       virtual void recycleKey(SymmetricKey* toRecycle);
+       virtual bool generateKey(SymmetricKey& key, RNG* rng = NULL);
+       virtual bool reconstructKey(SymmetricKey& key, const ByteString& serialisedData);
+
+       // Return cipher information
+       virtual size_t getBlockSize() const = 0;
+       virtual SymMode::Type getCipherMode();
+       virtual bool getPaddingMode();
+       virtual unsigned long getBufferSize();
+       virtual size_t getTagBytes();
+       virtual bool isStreamCipher();
+       virtual bool isBlockCipher();
+       virtual bool checkMaximumBytes(unsigned long bytes) = 0;
+
+protected:
+       // The current key
+       const SymmetricKey* currentKey;
+
+       // The current cipher mode
+       SymMode::Type currentCipherMode;
+
+       // The current padding
+       bool currentPaddingMode;
+
+       // The current counter bits
+       size_t currentCounterBits;
+
+       // The current tag bytes
+       size_t currentTagBytes;
+
+       // The current operation
+       enum
+       {
+               NONE,
+               ENCRYPT,
+               DECRYPT
+       }
+       currentOperation;
+
+       // The current number of bytes in buffer
+       unsigned long currentBufferSize;
+
+       // The current AEAD buffer
+       ByteString currentAEADBuffer;
+};
+
+#endif // !_SOFTHSM_V2_SYMMETRICALGORITHM_H
+
diff --git a/SoftHSMv2/src/lib/crypto/SymmetricKey.cpp b/SoftHSMv2/src/lib/crypto/SymmetricKey.cpp
new file mode 100644 (file)
index 0000000..550a144
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricKey.cpp
+
+ Base class for symmetric key classes
+ *****************************************************************************/
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+#include "SymmetricKey.h"
+#include "CryptoFactory.h"
+
+// Base constructors
+SymmetricKey::SymmetricKey(size_t inBitLen /* = 0 */)
+{
+       bitLen = inBitLen;
+}
+
+SymmetricKey::SymmetricKey(const SymmetricKey& in)
+{
+       keyData = in.keyData;
+       bitLen = in.bitLen;
+}
+
+// Set the key
+bool SymmetricKey::setKeyBits(const ByteString& keybits)
+{
+       if ((bitLen > 0) && ((keybits.size() * 8) != bitLen))
+       {
+               return false;
+       }
+
+       keyData = keybits;
+
+       return true;
+}
+
+// Get the key
+const ByteString& SymmetricKey::getKeyBits() const
+{
+       return keyData;
+}
+
+// Get the key check value
+ByteString SymmetricKey::getKeyCheckValue() const
+{
+       ByteString digest;
+
+       HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
+       if (hash == NULL) return digest;
+
+       if (!hash->hashInit() ||
+           !hash->hashUpdate(keyData) ||
+           !hash->hashFinal(digest))
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+               return digest;
+       }
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       digest.resize(3);
+
+       return digest;
+}
+
+// Serialisation
+ByteString SymmetricKey::serialise() const
+{
+       return keyData;
+}
+
+// Set the bit length
+void SymmetricKey::setBitLen(const size_t inBitLen)
+{
+       bitLen = inBitLen;
+}
+
+// Retrieve the bit length
+size_t SymmetricKey::getBitLen() const
+{
+       return bitLen;
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/SymmetricKey.h b/SoftHSMv2/src/lib/crypto/SymmetricKey.h
new file mode 100644 (file)
index 0000000..593040b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricKey.h
+
+ Base class for symmetric key classes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SYMMETRICKEY_H
+#define _SOFTHSM_V2_SYMMETRICKEY_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "Serialisable.h"
+
+class SymmetricKey : public Serialisable
+{
+public:
+       // Base constructors
+       SymmetricKey(size_t inBitLen = 0);
+
+       SymmetricKey(const SymmetricKey& in);
+
+       // Destructor
+       virtual ~SymmetricKey() { }
+
+       // Set the key
+       virtual bool setKeyBits(const ByteString& keybits);
+
+       // Get the key
+       virtual const ByteString& getKeyBits() const;
+
+       // Get the key check value
+       virtual ByteString getKeyCheckValue() const;
+
+       // Serialisation
+       virtual ByteString serialise() const;
+
+       // Set the bit length
+       virtual void setBitLen(const size_t inBitLen);
+
+       // Retrieve the bit length
+       virtual size_t getBitLen() const;
+
+protected:
+       // The key
+       ByteString keyData;
+
+       // The key length in bits
+       size_t bitLen;
+};
+
+#endif // !_SOFTHSM_V2_SYMMETRICKEY_H
+
diff --git a/SoftHSMv2/src/lib/crypto/odd.h b/SoftHSMv2/src/lib/crypto/odd.h
new file mode 100644 (file)
index 0000000..0ab2997
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ odd.h
+
+ Odd parity table
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ODD_H
+#define _SOFTHSM_V2_ODD_H
+
+const unsigned char odd_parity[256] = {
+       0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07,
+       0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E,
+       0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16,
+       0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F,
+       0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26,
+       0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F,
+       0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37,
+       0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E,
+       0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46,
+       0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F,
+       0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57,
+       0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E,
+       0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67,
+       0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E,
+       0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76,
+       0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F,
+       0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86,
+       0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F,
+       0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97,
+       0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E,
+       0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7,
+       0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE,
+       0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6,
+       0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF,
+       0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7,
+       0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE,
+       0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6,
+       0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF,
+       0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6,
+       0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF,
+       0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7,
+       0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE 
+};
+
+#endif // !_SOFTHSM_V2_ODD_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/AESTests.cpp b/SoftHSMv2/src/lib/crypto/test/AESTests.cpp
new file mode 100644 (file)
index 0000000..008560f
--- /dev/null
@@ -0,0 +1,1182 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AESTests.cpp
+
+ Contains test cases to test the AES implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "AESTests.h"
+#include "CryptoFactory.h"
+#include "AESKey.h"
+#include <stdio.h>
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AESTests);
+
+void AESTests::setUp()
+{
+       aes = NULL;
+
+       aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
+
+       // Check the return value
+       CPPUNIT_ASSERT(aes != NULL);
+}
+
+void AESTests::tearDown()
+{
+       if (aes != NULL)
+       {
+               CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
+       }
+
+       fflush(stdout);
+}
+
+void AESTests::testBlockSize()
+{
+       CPPUNIT_ASSERT(aes->getBlockSize() == 16);
+}
+
+void AESTests::testCBC()
+{
+       char testKeys128[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "89436760984679018453504364534464",
+               "49587346983643545706904580436731"
+       };
+
+       char testKeys192[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101213141516171819",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "096874395874290867409857496743857632098479834634",
+               "439867439058743095864395348375043296845094854983"
+       };
+
+       char testKeys256[][65] =
+       {
+               "0000000000000000000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20",
+               "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F",
+               "4394398576098257436095746985679043867498572406874967416846341641",
+               "4369006859867098670492857409386741095643756930847023587048579014"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "6CAEC72F5E101C66550215ACAB6B874C62E7BD074C0A09A8EE4562EFCB4E560A3E90FA0F50391087824FC27F57618E5C",
+                               "E20E3123AC64FCA5536E0A2DC48DBEBCECB3F260EFF4A0EB99D72F57EF38DED336EB9DD0B968D24C91E63974E7445A21",
+                               "C7910B1634DB493998608875A4652B20C64202ED507D9DBA06F62EB20A63C32FB6C9669D42A0AC29D773E6D40A63A2AC"
+                       },
+                       {
+                               "8F48A65BF638FEDB7E6F59BAC8C110FEBA933F106D564119B88569E758B7FB83",
+                               "125E1D93DC2C43A6FAFC508DB6F9A4A9F390D102C2300F0A3617CE95027BFAA3",
+                               "FACB8DEF1B476400DE9796D5058E9086ECF04C927F5C160161C7A34D8288EB3C"
+                       },
+                       {
+                               "C810E96482F109C9A05D2B1BEBAC7966BB7784F58A5478C1A07EC0DB39F6D87B",
+                               "2385391BB8F2DD97280B1FAEFACB6B5C4FE12A2274D6B967509CF18500A640D6",
+                               "47549520EADA1A5D931EACCC922F88BA2E386089BF97C790FD2CD38553334AE4"
+                       },
+                       {
+                               "A7D9EAE80224624188CAA7012140E946",
+                               "6ECD5C71ECA4AB9C3B71E91721CA2043",
+                               "2F77AA438E9259F268985668B00650E5"
+                       }
+               },
+               {
+                       {
+                               "FCB2FB6BF8ED8910F023A934EB9DA550E4D5B469D75B9390F4A207E54F29412450E52E980862DC80B89F6D1D10B68AA5",
+                               "7EF0F65513CFE3E0D21305E2ECCBB3554B0DE119720C5A86337E57F74795BC23ED9CB82A951DE3D00D7A0DC8997319DD",
+                               "5B83BFDB6EF3AEA5191F2EE3366EDE10480E9459C0DE2994DD9C6408A377DFFF8121A38CFD1AA864559B9A435A3BDD6D"
+                       },
+                       {
+                               "81D667193D42BF19C456F4A1F7070C047D94C7EE8136FA315F938162FDDA20C1",
+                               "2EFBA2B689C0F775097F98B569A1F20004F1A75F0C53473969DBE586ABCAE04D",
+                               "447326913AA4565951D987F59B48870DD9285EEFCF64B429C2220E4F3E0D9DE2"
+                       },
+                       {
+                               "891DF30BAEA2D24408A9C788D59DBAC7A6F34311813216311E18E9ED7122DB1A",
+                               "F1629B62ECDF3CDAA3DA0EBB31EE37691AF4EB2B6F9CF04A9861935B2C167D02",
+                               "C7BD348D5E6696CB8BA813B96EA5C42C5C3C3629D18FC9DAF1B50A0AE4843C5B"
+                       },
+                       {
+                               "91C44D109D46C8E8656793680D43BE94",
+                               "E68D8E49A19F155B7ED7253120B0D117",
+                               "FAED8666F695C85283ECF51C96DB41CE"
+                       }
+               },
+               {
+                       {
+                               "0CCFB49FE2B7E93A556E56B2C616885FBB0515F55A4210FE2F492A4775F078655CB21691CA6A54819C2D885954809D00",
+                               "2FC6C785D683FC35304DD161A21FA1B256F9FBB2817F1F3BEBCE7C1E292EC6999641AA6953C0FAB6DFC2942CABD32DFB",
+                               "31FAF4E3DA19D2372666AC635FFE361E33AD7865AEF616273D8F3B471F77A0998C6A41497168A65F621D912C54A4AF28"
+                       },
+                       {
+                               "0B3842152A6365ED14AD952ABBBAF0EED2E8F36250DD25DDA301490FDE05219B",
+                               "696BF21A887A04E194DCC18719E1BD623D8BD25A0CEF5EC2E21312ACE6C81F40",
+                               "A2C8E61471EC80FE39AC0D8F720FEA8F2D23D04596A751C755E51CD357BCA5E0"
+                       },
+                       {
+                               "5E0EA3AFBE191A16854C7960F087958F577EA4F80160F521A12D2211FAC25E16",
+                               "F5475B4FD48F969123C9F7FB08C7E902CCA282F167BBAFF1A7C7EDDB7BCBAC76",
+                               "380CB860EC6DEF4F9329F4BE826DE1FE61A71629DD978F00BEFB349ACBD0BAD8"
+                       },
+                       {
+                               "BA1452E755E6A43E43B10DD2C1530093",
+                               "07CA52926D4E8F2F6055E6E0251CB9E5",
+                               "AB99E5FEE195B4433667AD3074A9322E"
+                       }
+               },
+               {
+                       {
+                               "D2D46E577723B30E6B5FC96DC18B2C55E0EACCB07CE07C7F30FD113A987E2A2059AB7DF8985C1AE525EFAD9CE111893C",
+                               "CC5B220688AC0231DBC03C8886C0D0109840B9E58FBB1A6B6C261ED9E7979E951818033A25778FF328786D1777790078",
+                               "4B4A0B3D6D4E770BECC574BF66CD401942DC4D0DCD0EC65F99B2925B688BB217FCB5C946BE986C440C93279F4670CD43"
+                       },
+                       {
+                               "29C76D62D3C4F7FECCBFD7A73B06E2ECA7AA3B2D4BE79EC945B0B88C813264D8",
+                               "B898DCE11F3D6BB2182208E0BBBA7F404FE415D4D6D0772960E7CE3549B9899C",
+                               "11E9552009836B51F241E972D680A9F397260163D9D5369BFC1B136FB4206966"
+                       },
+                       {
+                               "539FC6EDAE21EDDC1CC4650367F527467916A6990E540146238AA9CD6B3B4ADE",
+                               "2D9DE2BC47DAFCF7867134110C541EBCD72D67B1B23DEF6805DBFF4A4D90EF91",
+                               "BF484690835FF61C4A7873A996EEB91F553978A40360E192273D3923E04DFE1E"
+                       },
+                       {
+                               "4910EFFFBF571C98D51802F04A42213E",
+                               "EDD1880FC4D41293BC74B98AF3D8A010",
+                               "F8BCC258A6CD7FAA4EDF16A3CF5573C4"
+                       }
+               },
+               {
+                       {
+                               "C2061BD0B4274B5CB4E408B492991F4195FDBFCDED1BC57442151B182BA6E8075AAF858F357C262E0034B9B5F839D823",
+                               "6EEFEBCC9F8C607D21A158E23980EFA6EC234DC6EA668A446F467F4AE87521F18DC1800D87A5EBC63C444F810557B61D",
+                               "00C952BA54614A1F11B0D59F3F469A859F62CCE0D35073B91B461302A7F37BD0B23401482DFCEE66ABD12C05615C9862"
+                       },
+                       {
+                               "B36553D93EEF04AE247DBCBDDB8C039FFAC8AC1B0EF14C2E4BA653F089924451",
+                               "90670C9DE58F95431591FA2BE8EA1B4B3F5BDBFC0B5199F94A41E4FC7B6B1645",
+                               "A065415413D3A08E4B42A3F2681B8D122167A1E3F92D38C305761D9BF80131F1"
+                       },
+                       {
+                               "12A758F161543F2842138B8C2453C3A05A90BE9F92CB3DD10C40AB9D1D746B49",
+                               "DF1F4DDFFE1032C812FC6F35AB2B3A7B0E8D26DA49DEC8F5E08D108DB1283BEA",
+                               "FDCB66159E1B5CF1BE9F7271EF2C35D5E9F7485E32D16C6AC865E64619DB8724"
+                       },
+                       {
+                               "1FC224DCB64848B5E8F9FB91C542991F",
+                               "1F8C5F65F9205098B47E26894B9154D9",
+                               "19763CAC206EDFDEBEDAD9C274DEE1C1"
+                       }
+               }
+       };
+
+       char testIV[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "69836472094875029486750948672066",
+               "48670943876904867104398574908554"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+               ByteString keyData128(testKeys128[i]);
+               ByteString keyData192(testKeys192[i]);
+               ByteString keyData256(testKeys256[i]);
+
+               AESKey aesKey128(128);
+               CPPUNIT_ASSERT(aesKey128.setKeyBits(keyData128));
+               AESKey aesKey192(192);
+               CPPUNIT_ASSERT(aesKey192.setKeyBits(keyData192));
+               AESKey aesKey256(256);
+               CPPUNIT_ASSERT(aesKey256.setKeyBits(keyData256));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+                       // Test 128-bit key
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey128, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey128, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 192-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey192, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey192, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 256-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey256, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey256, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
+
+void AESTests::testECB()
+{
+       char testKeys128[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "89436760984679018453504364534464",
+               "49587346983643545706904580436731"
+       };
+
+       char testKeys192[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101213141516171819",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "096874395874290867409857496743857632098479834634",
+               "439867439058743095864395348375043296845094854983"
+       };
+
+       char testKeys256[][65] =
+       {
+               "0000000000000000000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20",
+               "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F",
+               "4394398576098257436095746985679043867498572406874967416846341641",
+               "4369006859867098670492857409386741095643756930847023587048579014"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "6CAEC72F5E101C66550215ACAB6B874CD26479922B98D9839D7DA729B557ABA00143DB63EE66B0CDFF9F69917680151E",
+                               "E20E3123AC64FCA5536E0A2DC48DBEBC0E4E53BDA45FFC97C677951A891A6B7502BB292527E726FD51EB29894D6F0AAD",
+                               "C7910B1634DB493998608875A4652B205750B3B761DA7718E120C23A575F7D821F788FE6D86C317549697FBF0C07FA43"
+                       },
+                       {
+                               "8F48A65BF638FEDB7E6F59BAC8C110FE0E5E6370CBEFACFA0D7A5744030A481B",
+                               "125E1D93DC2C43A6FAFC508DB6F9A4A933738D14C219340D5F4D7203DEDCA7E1",
+                               "FACB8DEF1B476400DE9796D5058E90863A9A8C8BB2420B9A85BA3E8F87BB48F2"
+                       },
+                       {
+                               "C810E96482F109C9A05D2B1BEBAC79660143DB63EE66B0CDFF9F69917680151E",
+                               "2385391BB8F2DD97280B1FAEFACB6B5C02BB292527E726FD51EB29894D6F0AAD",
+                               "47549520EADA1A5D931EACCC922F88BA1F788FE6D86C317549697FBF0C07FA43"
+                       },
+                       {
+                               "A7D9EAE80224624188CAA7012140E946",
+                               "6ECD5C71ECA4AB9C3B71E91721CA2043",
+                               "2F77AA438E9259F268985668B00650E5"
+                       }
+               },
+               {
+                       {
+                               "8947CE273536C8A4D1E878F38371B9A8D2B3B45496779386CBA32CA70001D6AA6CC00A66D2AD83FFD76E9A2BCAD89A01",
+                               "B151340CFECADA3AE176637D0A78686E2063E1A602C85D03AE648BDF4FA57C36F7F1878D088644BD5FB43D3C0FE1C30C",
+                               "C19AE024C8F6B8E3383F675DF463512E273AAD7D0B88F22D5225EF09D2E37118D45D7C5AA26BCA9D6B1D5DDBF68F9EF6"
+                       },
+                       {
+                               "16C30BBAE7CDB2EE1E02275B79A064F6EE69FB37C8E039400435782F550CF86A",
+                               "F6C869D28D2D167C50BEE8F605D33021CB9173567B8B4AB3EEC68F0298324B78",
+                               "07DB563F7E31F1E670A02F97E8D120C7EE3FCEBBF2FDC2D37FC17D93ED1A778B"
+                       },
+                       {
+                               "52902B599686234833C4D420A9BF17FF6CC00A66D2AD83FFD76E9A2BCAD89A01",
+                               "B17FA9EA89D5578A844B3D82891330B1F7F1878D088644BD5FB43D3C0FE1C30C",
+                               "74BC55BE85291E0D1FA4A4444051CF65D45D7C5AA26BCA9D6B1D5DDBF68F9EF6"
+                       },
+                       {
+                               "3F00CAAC6FA432A7C1826CA4DA7C55D6",
+                               "9C2DBF449FF2C4AC1CFD7C43D200D33A",
+                               "E2183AB600A986806D86ADA4EE38E562"
+                       }
+               },
+               {
+                       {
+                               "23741EF993CBA04E5C67B42A16CA4D100BA6DF745E6D90818500DEC1CFC9811DBD3ACBFC853ED5DE825266C3B1883EC4",
+                               "F14D0EB7DFDB9B8960B0E47D7F4828E8756C38BA83655AAC466986ECB229A66FA390265A4BF5F50A8DFFAD253701E418",
+                               "0AAE579A796C94AF4FFB9D7C71381CB5E68E15465F30D7085A72D0CCEC7030BBC9CB7B3859E1A550BCBF11B624022C56"
+                       },
+                       {
+                               "AFCD6801459845C88548CC337BDD4D8B87E81D9D6AC945E14E3C4E0AC976A4B9",
+                               "117129A4775FC84E703F2F2C54B1B55DC4A79241F6CB0A37A8D551D71983D944",
+                               "1128250DA7C9A1BBE6A61AC01F28D4D9E3027C3625BD5514AE5DFE4B9132DAFA"
+                       },
+                       {
+                               "B275BDAF14AE286643C533258343F822BD3ACBFC853ED5DE825266C3B1883EC4",
+                               "93ACFCCFE2C4736B6492A673A59DACE2A390265A4BF5F50A8DFFAD253701E418",
+                               "2C2165E6491662A855FD7A20CDFF23BDC9CB7B3859E1A550BCBF11B624022C56"
+                       },
+                       {
+                               "30BBF52D760BAEA653FD03E5E84E583A",
+                               "F5F55DF3FC4D9CF2A2829BACA774A51A",
+                               "7EE196D148C11FA4998A90C6C7932395"
+                       }
+               },
+               {
+                       {
+                               "44C2B3344B002BB7A6994E1C74CC7BA70CE55BF44FD96506B553F0EFD3FE02B28329D59D480B0C1714A0DC60EB9FA8CE",
+                               "568C7627FD2519BE6031F052DE8F680860F7680460E92A524EA912174BE17B1337D593DEF15FB5BA64F03D1AAE276775",
+                               "99E36C0097BCFE41945C064EFA476FF4AA6048F909BEDE32A649F1035A2FB83CD601D09C3FDB36BC61B8CDE5BDD73804"
+                       },
+                       {
+                               "D748E8E93D29775BD8831E3BC1E1ABF75F484C7CC693521A66A5AB1637822E40",
+                               "010103778E123E5140F8D0356DA831E1587DB7E416AE9FAD14C6E2F78DC83148",
+                               "A8B8926E8FB762A1AB8CD9FA08507D77872C8EAAAFF3527572F49497B8B366C9"
+                       },
+                       {
+                               "CFF3212C7E94C2DD65EC1CDC998D6C4B8329D59D480B0C1714A0DC60EB9FA8CE",
+                               "324D16FEEC9DCA75A80F4B80175F8A7537D593DEF15FB5BA64F03D1AAE276775",
+                               "850567F4F0200CFBF88F1A6D35CAF6D9D601D09C3FDB36BC61B8CDE5BDD73804"
+                       },
+                       {
+                               "417F142D7609AE701B3D263FFECE4502",
+                               "E0DC994D8DC01C4EB2ECD19AD120C3D1",
+                               "FB26CC4E48B40EAB755FF65164EFB406"
+                       }
+               },
+               {
+                       {
+                               "048AEE75741BC60D01B512A53FEE97238F294743E7A351FAF589DD9E040BB8AF0F59D8F60E9C700F10025B5E69828819",
+                               "67FB10E52640B1E060F3D7868524721AC375DC76628B0D79C5F40ADC653FC001B50C33356548289D3E70EB7FBC0E2B56",
+                               "31953FF249D7519D3C39FB21D70A41033286A320193CC938C5ACBBCA2B25340829799212E3CABACE0BFD4424427705AB"
+                       },
+                       {
+                               "8D8D50FA4619F0E1B821DCA4ACBDFD46AE92D76A0B95A0331D61C4A7032D9705",
+                               "10685E8F632AC41D92E3A0403BB20C79868BD6F94691226EC54D7220C45E7233",
+                               "C5FF99FD1BC2BFDBEA62894B279DE6CBF51CCD00362A557DB9D9102DAF623A50"
+                       },
+                       {
+                               "0330B8FF58E4E6E956B4F81F7A4770200F59D8F60E9C700F10025B5E69828819",
+                               "C79BABE5B34B305B05E38013DC5568F7B50C33356548289D3E70EB7FBC0E2B56",
+                               "98BEE460FF803288C898A900DD08CE2529799212E3CABACE0BFD4424427705AB"
+                       },
+                       {
+                               "9A4FD3A26DD0D3A12F224E5E7A06EB76",
+                               "B86FE6F088C3A6497F21BCB29DB703D1",
+                               "313CC604B301DACA48CDB6F405AA7938"
+                       }
+               }
+       };
+
+       char testIV[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "69836472094875029486750948672066",
+               "48670943876904867104398574908554"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+               ByteString keyData128(testKeys128[i]);
+               ByteString keyData192(testKeys192[i]);
+               ByteString keyData256(testKeys256[i]);
+
+               AESKey aesKey128(128);
+               CPPUNIT_ASSERT(aesKey128.setKeyBits(keyData128));
+               AESKey aesKey192(192);
+               CPPUNIT_ASSERT(aesKey192.setKeyBits(keyData192));
+               AESKey aesKey256(256);
+               CPPUNIT_ASSERT(aesKey256.setKeyBits(keyData256));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+                       // Test 128-bit key
+
+                       // Get the reference for the encrypted data
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey128, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey128, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 192-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey192, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey192, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 256-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our AES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(aes->encryptInit(&aesKey256, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(aes->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(aes->decryptInit(&aesKey256, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(aes->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
+
+void AESTests::testCTR()
+{
+       // Test vectors from RFC3686
+
+       char testKeys128[][33] =
+       {
+               "AE6852F8121067CC4BF7A5765577F39E",
+               "7E24067817FAE0D743D6CE1F32539163",
+               "7691BE035E5020A8AC6E618529F9A0DC"
+       };
+
+       char testKeys192[][49] =
+       {
+               "16AF5B145FC9F579C175F93E3BFB0EED863D06CCFDB78515",
+               "7C5CB2401B3DC33C19E7340819E0F69C678C3DB8E6F6A91A",
+               "02BF391EE8ECB159B959617B0965279BF59B60A786D3E0FE"
+       };
+
+       char testKeys256[][65] =
+       {
+               "776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104",
+               "F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884",
+               "FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D"
+       };
+
+       char testData[][256] =
+       {
+               "53696E676C6520626C6F636B206D7367",
+               "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+               "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223"
+       };
+
+       char testResult[3][3][256] =
+       {
+               {
+                       "E4095D4FB7A7B3792D6175A3261311B8",
+                       "4B55384FE259C9C84E7935A003CBE928",
+                       "145AD01DBF824EC7560863DC71E3E0C0"
+               },
+               {
+                       "5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28",
+                       "453243FC609B23327EDFAAFA7131CD9F8490701C5AD4A79CFC1FE0FF42F4FB00",
+                       "F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C"
+               },
+               {
+                       "C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F",
+                       "96893FC55E5C722F540B7DD1DDF7E758D288BC95C69165884536C811662F2188ABEE0935",
+                       "EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8"
+               }
+       };
+
+       char testCB[3][3][33] =
+       {
+               {
+                       "00000030000000000000000000000001",
+                       "0000004836733C147D6D93CB00000001",
+                       "00000060DB5672C97AA8F0B200000001"
+               },
+               {
+                       "006CB6DBC0543B59DA48D90B00000001",
+                       "0096B03B020C6EADC2CB500D00000001",
+                       "00FAAC24C1585EF15A43D87500000001"
+               },
+               {
+                       "00E0017B27777F3F4A1786F000000001",
+                       "0007BDFD5CBD60278DCC091200000001",
+                       "001CC5B751A51D70A1C1114800000001"
+               }
+       };
+
+       for (int i = 0; i < 3; i++)
+       {
+               ByteString keyData128(testKeys128[i]);
+               ByteString keyData192(testKeys192[i]);
+               ByteString keyData256(testKeys256[i]);
+
+               AESKey aesKey128(128);
+               CPPUNIT_ASSERT(aesKey128.setKeyBits(keyData128));
+               AESKey aesKey192(192);
+               CPPUNIT_ASSERT(aesKey192.setKeyBits(keyData192));
+               AESKey aesKey256(256);
+               CPPUNIT_ASSERT(aesKey256.setKeyBits(keyData256));
+
+
+               ByteString plainText(testData[i]), shsmPlainText;
+               ByteString CB;
+               ByteString cipherText;
+               ByteString shsmCipherText, OB;
+
+               // Test 128-bit key
+               CB = ByteString(testCB[i][0]);
+               cipherText = ByteString(testResult[i][0]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey128, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey128, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+               // Test 192-bit key
+               CB = ByteString(testCB[i][1]);
+               cipherText = ByteString(testResult[i][1]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey192, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey192, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+               // Test 256-bit key
+               CB = ByteString(testCB[i][2]);
+               cipherText = ByteString(testResult[i][2]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey256, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey256, SymMode::CTR, CB));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+       }
+}
+
+#ifdef WITH_AES_GCM
+void AESTests::testGCM()
+{
+       // Test vectors from NIST via Botan
+
+       char test128[8][6][256] =
+       {
+               {
+                       "00000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "",
+                       "",
+                       "10",
+                       "58E2FCCEFA7E3061367F1D57A4E7455A"
+               },
+               {
+                       "00000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "00000000000000000000000000000000",
+                       "",
+                       "10",
+                       "0388DACE60B6A392F328C2B971B2FE78AB6E47D42CEC13BDF53A67B21257BDDF"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "CAFEBABEFACEDBADDECAF888",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255",
+                       "",
+                       "10",
+                       "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "CAFEBABEFACEDBADDECAF888",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39",
+                       "FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2",
+                       "10",
+                       "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E0915BC94FBC3221A5DB94FAE95AE7121A47"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "CAFEBABEFACEDBAD",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39",
+                       "FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2",
+                       "10",
+                       "61353B4C2806934A777FF51FA22A4755699B2A714FCDC6F83766E5F97B6C742373806900E49F24B22B097544D4896B424989B5E1EBAC0F07C23F45983612D2E79E3B0785561BE14AACA2FCCB"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "9313225DF88406E555909C5AFF5269AA6A7A9538534F7DA1E4C303D2A318A728C3C0C95156809539FCF0E2429A6B525416AEDBF5A0DE6A57A637B39B",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39",
+                       "FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2",
+                       "10",
+                       "8CE24998625615B603A033ACA13FB894BE9112A5C3A211A8BA262A3CCA7E2CA701E4A9A4FBA43C90CCDCB281D48C7C6FD62875D2ACA417034C34AEE5619CC5AEFFFE0BFA462AF43C1699D050"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "CAFEBABEFACEDBAD",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39",
+                       "FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2",
+                       "C",
+                       "61353B4C2806934A777FF51FA22A4755699B2A714FCDC6F83766E5F97B6C742373806900E49F24B22B097544D4896B424989B5E1EBAC0F07C23F45983612D2E79E3B0785561BE14A"
+               },
+               {
+                       "FEFFE9928665731C6D6A8F9467308308",
+                       "9313225DF88406E555909C5AFF5269AA6A7A9538534F7DA1E4C303D2A318A728C3C0C95156809539FCF0E2429A6B525416AEDBF5A0DE6A57A637B39B",
+                       "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39",
+                       "FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2",
+                       "C",
+                       "8CE24998625615B603A033ACA13FB894BE9112A5C3A211A8BA262A3CCA7E2CA701E4A9A4FBA43C90CCDCB281D48C7C6FD62875D2ACA417034C34AEE5619CC5AEFFFE0BFA462AF43C"
+               }
+       };
+
+       char test192[8][6][256] =
+       {
+               {
+                       "000000000000000000000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "",
+                       "",
+                       "10",
+                       "cd33b28ac773f74ba00ed1f312572435"
+               },
+               {
+                       "000000000000000000000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "00000000000000000000000000000000",
+                       "",
+                       "10",
+                       "98e7247c07f0fe411c267e4384b0f6002ff58d80033927ab8ef4d4587514f0fb"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+                       "",
+                       "10",
+                       "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade2569924a7c8587336bfb118024db8674a14"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda27102519498e80f1478f37ba55bd6d27618c"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "cafebabefacedbad",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f765dcc57fcf623a24094fcca40d3533f8"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373bdcf566ff291c25bbb8568fc3d376a6d9"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "C",
+                       "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda27102519498e80f1478f37ba55bd"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+                       "cafebabefacedbad",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "C",
+                       "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f765dcc57fcf623a24094fcca4"
+               }
+       };
+
+       char test256[8][6][256] =
+       {
+               {
+                       "0000000000000000000000000000000000000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "",
+                       "",
+                       "10",
+                       "530f8afbc74536b9a963b4f1c4cb738b"
+               },
+               {
+                       "0000000000000000000000000000000000000000000000000000000000000000",
+                       "000000000000000000000000",
+                       "00000000000000000000000000000000",
+                       "",
+                       "10",
+                       "cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+                       "",
+                       "10",
+                       "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015adb094dac5d93471bdec1a502270e3cc6c"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f66276fc6ece0f4e1768cddf8853bb2d551b"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "cafebabefacedbad",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f3a337dbf46a792c45e454913fe2ea8f2",
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "10",
+                       "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3fa44a8266ee1c8eb0c8b5d4cf5ae9f19a"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "cafebabefacedbaddecaf888",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "C",
+                       "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f66276fc6ece0f4e1768cddf8853"
+               },
+               {
+                       "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+                       "cafebabefacedbad",
+                       "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+                       "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+                       "C",
+                       "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f3a337dbf46a792c45e454913"
+               }
+       };
+
+       for (int i = 0; i < 8; i++)
+       {
+               ByteString keyData128(test128[i][0]);
+               ByteString keyData192(test192[i][0]);
+               ByteString keyData256(test256[i][0]);
+
+               AESKey aesKey128(128);
+               CPPUNIT_ASSERT(aesKey128.setKeyBits(keyData128));
+               AESKey aesKey192(192);
+               CPPUNIT_ASSERT(aesKey192.setKeyBits(keyData192));
+               AESKey aesKey256(256);
+               CPPUNIT_ASSERT(aesKey256.setKeyBits(keyData256));
+
+               ByteString IV;
+               ByteString plainText;
+               ByteString AAD;
+               size_t tagBits;
+               ByteString cipherText;
+
+               ByteString shsmPlainText;
+               ByteString shsmCipherText;
+               ByteString OB;
+
+               // Test 128-bit key
+               IV = ByteString(test128[i][1]);
+               plainText = ByteString(test128[i][2]);
+               AAD = ByteString(test128[i][3]);
+               tagBits = ByteString(test128[i][4]).long_val();
+               cipherText = ByteString(test128[i][5]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey128, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey128, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               CPPUNIT_ASSERT(OB.size() == 0);
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+               // Test 192-bit key
+               IV = ByteString(test192[i][1]);
+               plainText = ByteString(test192[i][2]);
+               AAD = ByteString(test192[i][3]);
+               tagBits = ByteString(test192[i][4]).long_val();
+               cipherText = ByteString(test192[i][5]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey192, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey192, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               CPPUNIT_ASSERT(OB.size() == 0);
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+               // Test 256-bit key
+               IV = ByteString(test256[i][1]);
+               plainText = ByteString(test256[i][2]);
+               AAD = ByteString(test256[i][3]);
+               tagBits = ByteString(test256[i][4]).long_val();
+               cipherText = ByteString(test256[i][5]);
+
+               // Now, do the same thing using our AES implementation
+               shsmCipherText.wipe();
+               CPPUNIT_ASSERT(aes->encryptInit(&aesKey256, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->encryptUpdate(plainText, OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(aes->encryptFinal(OB));
+               shsmCipherText += OB;
+
+               CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+               // Check that we can get the plain text
+               shsmPlainText.wipe();
+               CPPUNIT_ASSERT(aes->decryptInit(&aesKey256, SymMode::GCM, IV, true, 0, AAD, tagBits));
+
+               CPPUNIT_ASSERT(aes->decryptUpdate(shsmCipherText, OB));
+               CPPUNIT_ASSERT(OB.size() == 0);
+
+               CPPUNIT_ASSERT(aes->decryptFinal(OB));
+               shsmPlainText += OB;
+
+               CPPUNIT_ASSERT(shsmPlainText == plainText);
+       }
+}
+#endif
+
+void AESTests::testWrap(const char testKeK[][128], const char testKey[][128], const char testCt[][128], const int testCnt, SymWrap::Type mode)
+{
+       for (int i = 0; i < testCnt; i++)
+       {
+               ByteString kekData(testKeK[i]);
+               ByteString keyData(testKey[i]);
+
+               AESKey aesKeK(kekData.size() * 8);
+               CPPUNIT_ASSERT(aesKeK.setKeyBits(kekData));
+
+               ByteString wrapped;
+               ByteString expectedCt(testCt[i]);
+               CPPUNIT_ASSERT(aes->wrapKey(&aesKeK, mode, keyData, wrapped));
+               CPPUNIT_ASSERT(wrapped.size() == expectedCt.size());
+               CPPUNIT_ASSERT(wrapped == expectedCt);
+
+               ByteString unwrapped;
+               CPPUNIT_ASSERT(aes->unwrapKey(&aesKeK, mode, wrapped, unwrapped));
+               CPPUNIT_ASSERT(unwrapped.size() == keyData.size());
+               CPPUNIT_ASSERT(unwrapped == keyData);
+/*
+       #ifdef HAVE_AES_KEY_WRAP_PAD
+               keyData.resize(20);
+               ByteString padwrapped;
+               CPPUNIT_ASSERT(aes->wrapKey(&aesKeK, SymWrap::AES_KEYWRAP_PAD, keyData, padwrapped));
+               CPPUNIT_ASSERT(padwrapped.size() == 32);
+
+               ByteString padunwrapped;
+               CPPUNIT_ASSERT(aes->unwrapKey(&aesKeK, SymWrap::AES_KEYWRAP_PAD, padwrapped, padunwrapped));
+               CPPUNIT_ASSERT(padunwrapped == keyData);
+       #endif
+*/
+       }
+}
+
+// RFC 3394 tests
+void AESTests::testWrapWoPad()
+{
+       char testKeK[][128] = {
+               "000102030405060708090A0B0C0D0E0F", // section 4.1
+               "000102030405060708090A0B0C0D0E0F1011121314151617", // section 4.2
+               "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", // section 4.3
+               "000102030405060708090A0B0C0D0E0F1011121314151617", // section 4.4
+               "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", // section 4.5
+               "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", // section 4.6
+       };
+       char testKey[][128] = {
+               "00112233445566778899AABBCCDDEEFF",
+               "00112233445566778899AABBCCDDEEFF",
+               "00112233445566778899AABBCCDDEEFF",
+               "00112233445566778899AABBCCDDEEFF0001020304050607",
+               "00112233445566778899AABBCCDDEEFF0001020304050607",
+               "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F"
+       };
+       char testCt[][128] = {
+               "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5",
+               "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D",
+               "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7",
+               "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2",
+               "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1",
+               "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21"
+       };
+
+       testWrap(testKeK, testKey, testCt, sizeof(testKeK) / 128, SymWrap::AES_KEYWRAP);
+}
+
+// RFC 5649 tests
+void AESTests::testWrapPad()
+{
+       char testKeK[][128] = {
+               "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8", // section 6 example 1
+               "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8", // section 6 example 2
+       };
+       char testKey[][128] = {
+               "C37B7E6492584340BED12207808941155068F738",
+               "466F7250617369"
+       };
+       char testCt[][128] = {
+               "138BDEAA9B8FA7FC61F97742E72248EE5AE6AE5360D1AE6A5F54F373FA543B6A",
+               "AFBEB0F07DFBF5419200F2CCB50BB24F"
+       };
+
+       testWrap(testKeK, testKey, testCt, sizeof(testKeK) / 128, SymWrap::AES_KEYWRAP_PAD);
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/AESTests.h b/SoftHSMv2/src/lib/crypto/test/AESTests.h
new file mode 100644 (file)
index 0000000..3a50b11
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ AESTests.h
+
+ Contains test cases to test the AES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_AESTESTS_H
+#define _SOFTHSM_V2_AESTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "SymmetricAlgorithm.h"
+
+class AESTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(AESTests);
+       CPPUNIT_TEST(testBlockSize);
+       CPPUNIT_TEST(testCBC);
+       CPPUNIT_TEST(testECB);
+       CPPUNIT_TEST(testCTR);
+#ifdef WITH_AES_GCM
+       CPPUNIT_TEST(testGCM);
+#endif
+#ifdef HAVE_AES_KEY_WRAP
+       CPPUNIT_TEST(testWrapWoPad);
+#endif
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       CPPUNIT_TEST(testWrapPad);
+#endif
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testBlockSize();
+       void testCBC();
+       void testECB();
+       void testCTR();
+#ifdef WITH_AES_GCM
+       void testGCM();
+#endif
+       void testWrapWoPad();
+       void testWrapPad();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // AES instance
+       SymmetricAlgorithm* aes;
+       void testWrap(const char testKeK[][128], const char testKey[][128], const char testCt[][128], const int testCnt, SymWrap::Type mode);
+};
+
+#endif // !_SOFTHSM_V2_AESTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/DESTests.cpp b/SoftHSMv2/src/lib/crypto/test/DESTests.cpp
new file mode 100644 (file)
index 0000000..bcb1c6b
--- /dev/null
@@ -0,0 +1,1164 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DESTests.cpp
+
+ Contains test cases to test the DES implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DESTests.h"
+#include "CryptoFactory.h"
+#include "DESKey.h"
+#include <stdio.h>
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DESTests);
+
+void DESTests::setUp()
+{
+       des = NULL;
+
+       des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES);
+
+       // Check the return value
+       CPPUNIT_ASSERT(des != NULL);
+}
+
+void DESTests::tearDown()
+{
+       if (des != NULL)
+       {
+               CryptoFactory::i()->recycleSymmetricAlgorithm(des);
+       }
+
+       fflush(stdout);
+}
+
+void DESTests::testBlockSize()
+{
+       CPPUNIT_ASSERT(des->getBlockSize() == 8);
+}
+
+void DESTests::testCBC()
+{
+#ifndef WITH_FIPS
+       char testKeys56[][17] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4698436794236871",
+               "0940278947239572"
+       };
+
+       char testKeys112[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "64398647034486943598534703463870",
+               "87406984068406984607412103517413"
+       };
+#endif
+
+       char testKeys168[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "643906874509874309687459084769847562436043696747",
+               "430135460496813044639085714376487549490586439575"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7",
+                               "ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7",
+                               "ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7"
+                       },
+                       {
+                               "F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64",
+                               "F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64",
+                               "F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64"
+                       },
+                       {
+                               "36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588",
+                               "36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588",
+                               "36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588"
+                       },
+                       {
+                               "B81DA29972385E55CB453A17B6D88D22",
+                               "B81DA29972385E55CB453A17B6D88D22",
+                               "B81DA29972385E55CB453A17B6D88D22"
+                       }
+               },
+               {
+                       {
+                               "EE16FFE3CC4D4589766FA0957FB728A75D44A00D9BEBE2D43C4D4F3A5AFDB49730CFD4DF46D3AEF6",
+                               "A070EE9DED89EE198E0E9B3CEB4879BB0244AB7FCD3450ED044BB5EE0AC8F7797383FDB8AAEF77B8",
+                               "E7C594590C9CA00B376B702CE3B92C3F699B3EEEB2CEA08FA551350C837BF031FCAF4E1E97450327"
+                       },
+                       {
+                               "D4142C47C700069F3E71EA6B1EF301B9B97261543ED75B32242C05A253B077B8",
+                               "102BBE7D93CD0EF66280D3FA1F2A3976FB9C4D1B155D19E4985ADB86015DDE8C",
+                               "600C3A75AC6EB4C4609BA6B7ED273ED56E59CD49FC911C33DD8DFCA384BAA462"
+                       },
+                       {
+                               "47452120CD84CC32FC72F3B8600E5C43EEE192A29BC6BCB7",
+                               "ADCF4292A32E51A7843CC8590E6934083A2CC847082FF2B4",
+                               "D0FA596AC00BDA870999FD3FA2494C3C8B40B261EB3066F6"
+                       },
+                       {
+                               "6BD20CDBE6E6ECAD6ED829FB43E92751",
+                               "AE4379E371E295F63423F861B59111F0",
+                               "2757FC58EDEEB8499EA9B49AB2729BAD"
+                       }
+               },
+               {
+                       {
+                               "298621D5237F6230067DE7871DDBA6991E85CA14AD661D21357240923604D23A6A4119277B75B331",
+                               "2C9F4FC0ACE7C8A4847472A0D5DDD42F36D3B2C46144B5A0ECDBB59806472E6257952DFD4DB9EBE5",
+                               "679A832C630207E76BC1FF8371C61CA2518E37FE97EDED1B171E3E11807250145736949368AC822B"
+                       },
+                       {
+                               "80FFD37B545675BB8C7CD317A73AB48CC0A39D3D9C11474EC3FD1220A066C034",
+                               "F9228036718792EE86A85626AB1BC05E17F9CE21FF5D1723D0442CE852F004C3",
+                               "D5F5F1EA7D8C2038FEDCBEDF157A5D2469A941FEC696D74DB8359CA5AECDD4CE"
+                       },
+                       {
+                               "1ABB1CC10F589D993030A978B1B7F44AD52FFFEBF23638CA",
+                               "D2423F54FA4978C95E4B13EF4DD6AA82DFD772F0FDAF5AD1",
+                               "8128EC49D71F5711E5304E7C4423C63AD0EFC45453B66583"
+                       },
+                       {
+                               "B9EE976AB97396047510C1DEA5C86A4B",
+                               "46BA1930042146B31BD8FAF3AE6F3414",
+                               "46EF3BCCA73E33C03D81BFE0DFFA7ABD"
+                       }
+               },
+               {
+                       {
+                               "30D1B2556D516F20C2FD117FE0355845FBB0B11ABE5922A7EAA19C3A48E30207218321B3F0F30A6D",
+                               "CBFA560297901DD691CDFDF98675BD7FF3A64FDCC0EF02F29C81105D3ECAC4E2803E2279F4476B35",
+                               "4A30EC10433BE3695DC2B064E6240419C7BF81F1EE7640D5E2FFFA106666A2CEBF18DB954A992B5E"
+                       },
+                       {
+                               "61FFB2E5A73170603E48F9823E6DF7105C9A909CC2F5CEDBEA7E60C076355B37",
+                               "8408BD722B12031D17A1645AA59B05E2A50F7002B19877D6EB1C9BB7107C523F",
+                               "97EF5791017B10CF07FB8144C19633522CBBE55DC63EF608F8734EE6484C0B0E"
+                       },
+                       {
+                               "7205DC463B3D5EC858C8E7A13844A1A8FF21C0D615CA56AF",
+                               "D5D08C1DC728A47CD55A2ACBB811294962022E745F4BCDF4",
+                               "7761189D73039A3F06BDDF00B308D7A43BE7BEA1CE9D042E"
+                       },
+                       {
+                               "1702428661BA4CFE686CFDEDFFAA6A27",
+                               "9218A89B0A7AEC7E6E2AF1CA493B2829",
+                               "6EEB9F7DDF66CED3DB74F7E8DE0CB2CD"
+                       }
+               },
+               {
+                       {
+                               "4FD3A4C759827F6E188E542B83A858026C17FD1DEF21477A964D122B62EE55FA9DB3CCF05A768C83",
+                               "F2C8B52652970805EE60ECECC8369C98443463F1C3A5A6357DFDFEE6B7F1EF0CF05523B5469E4555",
+                               "21FCBDC92C07F112D19742F5100F2A995E27CB282D73DF5CFEC802C629A279BD4E498C98D170003E"
+                       },
+                       {
+                               "3FD4C32A44DC0A9605A5A793C57E94826E80FC9E8E9620BBC2E02FE41A62A2D3",
+                               "4FC88F1E88C3B5A76CF6BE5FA8205BA6F7FA201F7C40E8F0F9CA156E140A4EC5",
+                               "CCE31260C967F4B9BB3D2D31F82320715E434C1313D911C58CE7E42AA78DA831"
+                       },
+                       {
+                               "714766BE5CB60DA99DC0BD4E7E655ADE7F26E45F372EF1BF",
+                               "00064542E2B4821B4E9173DA6FD1ABAE45C5E5CF26DB506D",
+                               "4D88D531C20E63A39372F275329BDBEBE15E7D2C32F2A98F"
+                       },
+                       {
+                               "4933917C9B56124914D2B76DE221BA13",
+                               "7F2D1CA9D942630FE1E954E4176E84A5",
+                               "9A46902F3997F0EB121981DAEC6D89C4"
+                       }
+               }
+       };
+
+       char testIV[][33] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4693867334098764",
+               "6209876098547207"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+#ifndef WITH_FIPS
+               ByteString keyData56(testKeys56[i]);
+               CPPUNIT_ASSERT(keyData56.size() == 8);
+               ByteString keyData112(testKeys112[i]);
+               CPPUNIT_ASSERT(keyData112.size() == 16);
+#endif
+               ByteString keyData168(testKeys168[i]);
+               CPPUNIT_ASSERT(keyData168.size() == 24);
+
+#ifndef WITH_FIPS
+               DESKey desKey56(56);
+               CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
+               DESKey desKey112(112);
+               CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
+#endif
+               DESKey desKey168(168);
+               CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+#ifndef WITH_FIPS
+                       // Test 56-bit key
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 112-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+#endif
+
+                       // Test 168-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::CBC, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
+
+void DESTests::testECB()
+{
+#ifndef WITH_FIPS
+       char testKeys56[][17] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4698436794236871",
+               "0940278947239572"
+       };
+
+       char testKeys112[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "64398647034486943598534703463870",
+               "87406984068406984607412103517413"
+       };
+#endif
+
+       char testKeys168[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "643906874509874309687459084769847562436043696747",
+               "430135460496813044639085714376487549490586439575"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0",
+                               "ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0",
+                               "ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0"
+                       },
+                       {
+                               "F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0",
+                               "F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0",
+                               "F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0"
+                       },
+                       {
+                               "36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0",
+                               "36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0",
+                               "36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0"
+                       },
+                       {
+                               "B81DA29972385E55EA1F3677CDC02D27",
+                               "B81DA29972385E55EA1F3677CDC02D27",
+                               "B81DA29972385E55EA1F3677CDC02D27"
+                       }
+               },
+               {
+                       {
+                               "278B2CA6259C30E180CCB62E69F0841F235507E2FB3404FC2BC223E37E32B3A78207EA5D3E19A5FD",
+                               "417579E3ABEF6F0D620B4FF88E2220457466420803140BFEFBA062A2A41D7C15061019377C6BFD8A",
+                               "A676D0404F0F105B2073B9DD19C8C434428098BFC5AF1292FE12477340395F118F45B5BE23F16C4E"
+                       },
+                       {
+                               "7D004390E5638E54077E2551B01BD52BFA1B98403ECE1AEF8207EA5D3E19A5FD",
+                               "391B84593FEA836450318A6E943F1C3A4A6BD74E5001EB7A061019377C6BFD8A",
+                               "DEAF58111ECCCB449F0C2564B52E360E4AACC8672ABBDF1A8F45B5BE23F16C4E"
+                       },
+                       {
+                               "A6947F9EF4159BAE636A70B904059BC38207EA5D3E19A5FD",
+                               "14ADFE212E27BF7F409395B45577F2C8061019377C6BFD8A",
+                               "FF87BF761FC159F4442B3B4593233BC48F45B5BE23F16C4E"
+                       },
+                       {
+                               "3A1777DAAAC85389EE0B499A90AE1739",
+                               "376E61DF2EAFE5B523964A03885AD085",
+                               "E4D81EE64FE8FB187EB7B5E80E075C73"
+                       }
+               },
+               {
+                       {
+                               "F105809DF621715F4D3492E1EEC4A7DE0775A0632ECC13429DF0DC695A60882FA47F93E855A1445B",
+                               "77C85215179312315997B4D0E997DB413176C80A8ED9F5EB9B726200224CE97C20A8A19F543BCCBD",
+                               "AF1477E32B5BB1CA46D26B6020B3B48DB0A90A97B1BA60F032ADA648296EC92DEE924AA617423FD1"
+                       },
+                       {
+                               "0FB3C3D9D93E0025F87909CD351D0116C0F684A204015E2CA47F93E855A1445B",
+                               "67A66DB3209C406D2FE31AF6C36D24C7B32D0F8F1EAFA90020A8A19F543BCCBD",
+                               "F85B1F07D788C59CD3DE6D562A175725DF596847ADEA8764EE924AA617423FD1"
+                       },
+                       {
+                               "243A34CD70CE3819B9510980B6EFF3EAA47F93E855A1445B",
+                               "997E145467B88D9D4C923797F539AC1620A8A19F543BCCBD",
+                               "836788D7AD1F879B405438775FFD6D76EE924AA617423FD1"
+                       },
+                       {
+                               "70856D6B67EE353F27EBB96462DACE63",
+                               "D02F2A92C175A58001D89C4AEC476384",
+                               "4ED379A40187826CAA90D2D6A05D5A9B"
+                       }
+               },
+               {
+                       {
+                               "C79F67ABCE6F741CF6D5B7B4870397779AEB89F48805DD1A28305E804A4A2B91114E1CF0C7FA91DA",
+                               "42956EA3B9415E8FE75B667A7C6B1ADF64D08E53C38DE733A776A97C7A8FC27E32945078552FA3E2",
+                               "3685365AD0F07609E13CCDE69CEDC8CCA0C37262A87B734286B9119643AC3BABE435BDA25919BE86"
+                       },
+                       {
+                               "09B882774309CC2B117586F5FA8BF7E4A5DA2A65E137665B114E1CF0C7FA91DA",
+                               "0E52A9ABE753758D3C4F6326A8F689282D1DAB8AF6FC8CFF32945078552FA3E2",
+                               "8DB6B9D50B5B8CE7DA56546CFF36C16BA3159E0EB7BD649AE435BDA25919BE86"
+                       },
+                       {
+                               "025F9704F6ACD844BCFC6EBA809CD871114E1CF0C7FA91DA",
+                               "1692C6A1DF9192C6D4125991EA9A9CBE32945078552FA3E2",
+                               "6B848E67225EDDCCD7E8EC89ACDAA0AFE435BDA25919BE86"
+                       },
+                       {
+                               "9D01CD89916AEE48AFE528A376E07AE9",
+                               "6FA6A689405048060D65E1B1240B76B7",
+                               "7EADEB7073D2EA995C5ED613C978817F"
+                       }
+               },
+               {
+                       {
+                               "A98D0E8E72C589D80D240F192CF65C30FF3A1AB9D8CE54B09AA249C72E395AC3B40F19A649C1B237",
+                               "33AC43C7A936665859431D18C089EE45F1356C34F5DF462D81BBFA42380A7E4F6732A473091A3673",
+                               "FD4F2F77CCE20147CD0932B2E2D8D5978523F6A03D59E31E1F678A5DA4C350132E94F199555C371E"
+                       },
+                       {
+                               "39453F3BF3C0CAE54279D96F4592359A5AEE6DD04D5F6162B40F19A649C1B237",
+                               "E2AFCEEFF2317C520D890D7F2CB91ACD99D5DCAEC9C409016732A473091A3673",
+                               "CB19BF88B2DEDDE981E048379A47BDF77ED5F815034CB07A2E94F199555C371E"
+                       },
+                       {
+                               "9D466BACFA69266F7CC26D2C8B8CD203B40F19A649C1B237",
+                               "265FDBCCF5F2325B3C8770ABEEECA4166732A473091A3673",
+                               "C61E9B86A8A663AE1566CFFCF2046D6B2E94F199555C371E"
+                       },
+                       {
+                               "380091B24160152B63EF067F6C189385",
+                               "548EB237B455CBA0100A5C52A6F28C2B",
+                               "066C3B0C5E6AF1E9BDD3DDAE5040F809"
+                       }
+               }
+       };
+
+       char testIV[][33] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4693867334098764",
+               "6209876098547207"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+#ifndef WITH_FIPS
+               ByteString keyData56(testKeys56[i]);
+               CPPUNIT_ASSERT(keyData56.size() == 8);
+               ByteString keyData112(testKeys112[i]);
+               CPPUNIT_ASSERT(keyData112.size() == 16);
+#endif
+               ByteString keyData168(testKeys168[i]);
+               CPPUNIT_ASSERT(keyData168.size() == 24);
+
+#ifndef WITH_FIPS
+               DESKey desKey56(56);
+               CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
+               DESKey desKey112(112);
+               CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
+#endif
+               DESKey desKey168(168);
+               CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+#ifndef WITH_FIPS
+                       // Test 56-bit key
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 112-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+#endif
+
+                       // Test 168-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::ECB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
+
+void DESTests::testOFB()
+{
+#ifndef WITH_FIPS
+       char testKeys56[][17] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4698436794236871",
+               "0940278947239572"
+       };
+
+       char testKeys112[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "64398647034486943598534703463870",
+               "87406984068406984607412103517413"
+       };
+#endif
+
+       char testKeys168[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "643906874509874309687459084769847562436043696747",
+               "430135460496813044639085714376487549490586439575"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846",
+                               "C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846",
+                               "C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846"
+                       },
+                       {
+                               "D83E5E8D823844AE48567490687546090EE32BBFE7E3542F",
+                               "D83E5E8D823844AE48567490687546090EE32BBFE7E3542F",
+                               "D83E5E8D823844AE48567490687546090EE32BBFE7E3542F"
+                       },
+                       {
+                               "E89FCA8099D6B1FF6795867965624526",
+                               "E89FCA8099D6B1FF6795867965624526",
+                               "E89FCA8099D6B1FF6795867965624526"
+                       },
+                       {
+                               "CA253BAC45D205E236",
+                               "CA253BAC45D205E236",
+                               "CA253BAC45D205E236"
+                       }
+               },
+               {
+                       {
+                               "3E9FB188FC11138D05109EA396CA48E1681DF27A857C3C4A9E92D3DC85A5F313",
+                               "3440BEFCF35DC87716D8440F71BAF9ACD0441E10B9E5B525F0584499620086E2",
+                               "DDB35281888DF064195C42D45E4E2571AD62113A228B5107D1AC849861C199C0"
+                       },
+                       {
+                               "233FC5D8B6F005B02500727078E84ED16C1B0474D7277E45",
+                               "29E0CAACB9BCDE4A36C8A8DC9F98FF9CD442E81EEBBEF72A",
+                               "C01326D1C26CE659394CAE07B06C2341A964E73470D01308"
+                       },
+                       {
+                               "139E51D5AD1EF0E10AC3809975FF4DFE",
+                               "19415EA1A2522B1B190B5A35928FFCB3",
+                               "F0B2B2DCD9821308168F5CEEBD7B206E"
+                       },
+                       {
+                               "3124A0F9711A44FC5B",
+                               "3BFBAF8D7E569F0648",
+                               "D20843F00586A71547"
+                       }
+               },
+               {
+                       {
+                               "E376288A10BD52CB7162ADA9A732D24B574B1E7CB4FF5C791FFEA2E481AD3049",
+                               "FD82CFAE85B8581FFCF489F467D94B1B4FAAAEDDE4EC531ABD30D7EA235896AA",
+                               "24D9411BA456571900244AEA3EA7159BAA96522B6F891606A8D9A559FE218A9B"
+                       },
+                       {
+                               "FED65CDA5A5C44F65172417A4910D47B534DE872E6A41E76",
+                               "E022BBFECF594E22DCE4652789FB4D2B4BAC58D3B6B71115",
+                               "3979354BEEB741242034A639D08513ABAE90A4253DD25409"
+                       },
+                       {
+                               "CE77C8D741B2B1A77EB1B3934407D754",
+                               "D0832FF3D4B7BB73F32797CE84EC4E04",
+                               "09D8A146F559B4750FF754D0DD921084"
+                       },
+                       {
+                               "ECCD39FB9DB605BA2F",
+                               "F239DEDF08B30F6EA2",
+                               "2B62506A295D00685E"
+                       }
+               },
+               {
+                       {
+                               "740A4786C73A7C6B52DAF270161895E13B4437C56B9837827C2FE237532F4C19",
+                               "581B63C58404AEBECFDFD51D74A79836C11514685B47F3B02A2419AF0AA8C625",
+                               "D5FCB196868673D136D480E0B6EFC33C589131D87A4AC004A6E0DE8ADC8DE611"
+                       },
+                       {
+                               "69AA33D68DDB6A5672CA1EA3F83A93D13F42C1CB39C3758D",
+                               "45BB1795CEE5B883EFCF39CE9A859E06C513E266091CB1BF",
+                               "C85CC5C6CC6765EC16C46C3358CDC50C5C97C7D62811820B"
+                       },
+                       {
+                               "590BA7DB96359F075D09EC4AF52D90FE",
+                               "751A8398D50B4DD2C00CCB2797929D29",
+                               "F8FD51CBD78990BD39079EDA55DAC623"
+                       },
+                       {
+                               "7BB156F74A312B1A0C",
+                               "57A072B4090FF9CF91",
+                               "DA47A0E70B8D24A068"
+                       }
+               },
+               {
+                       {
+                               "0855A84EAD2176C3F10B9DCFC8D1A379AF616FC5C5CD4E6D434353C52832F9F6",
+                               "A8420E97462B0215AAC1DB0835D4064C6A8B123327FC396C9520BEA70B59B412",
+                               "3461DEDF1B4893E16706900E1DDBE351E90C1300B9B01E8A518A01AD56E9AC8C"
+                       },
+                       {
+                               "15F5DC1EE7C060FED11B711C26F3A549AB6799CB97960C62",
+                               "B5E27AC70CCA14288AD137DBDBF6007C6E8DE43D75A77B63",
+                               "29C1AA8F51A985DC47167CDDF3F9E561ED0AE50EEBEB5C85"
+                       },
+                       {
+                               "25544813FC2E95AFFED883F52BE4A666",
+                               "8543EECA1724E179A512C532D6E10353",
+                               "19603E824A47708D68D58E34FEEEE64E"
+                       },
+                       {
+                               "07EEB93F202A21B2AF",
+                               "A7F91FE6CB205564F4",
+                               "3BDACFAE9643C49039"
+                       }
+               }
+       };
+
+       char testIV[][33] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4693867334098764",
+               "6209876098547207"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+#ifndef WITH_FIPS
+               ByteString keyData56(testKeys56[i]);
+               CPPUNIT_ASSERT(keyData56.size() == 8);
+               ByteString keyData112(testKeys112[i]);
+               CPPUNIT_ASSERT(keyData112.size() == 16);
+#endif
+               ByteString keyData168(testKeys168[i]);
+               CPPUNIT_ASSERT(keyData168.size() == 24);
+
+#ifndef WITH_FIPS
+               DESKey desKey56(56);
+               CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
+               DESKey desKey112(112);
+               CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
+#endif
+               DESKey desKey168(168);
+               CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+#ifndef WITH_FIPS
+                       // Test 56-bit key
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 112-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+#endif
+
+                       // Test 168-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::OFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
+
+void DESTests::testCFB()
+{
+#ifndef WITH_FIPS
+       char testKeys56[][17] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4698436794236871",
+               "0940278947239572"
+       };
+
+       char testKeys112[][33] =
+       {
+               "00000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F10",
+               "404142434445464748494A4B4C4D4E4F",
+               "64398647034486943598534703463870",
+               "87406984068406984607412103517413"
+       };
+#endif
+
+       char testKeys168[][49] =
+       {
+               "000000000000000000000000000000000000000000000000",
+               "0102030405060708090A0B0C0D0E0F101112131415161718",
+               "404142434445464748494A4B4C4D4E4F5051525354555657",
+               "643906874509874309687459084769847562436043696747",
+               "430135460496813044639085714376487549490586439575"
+       };
+
+       char testData[][256] =
+       {
+               "4938673409687134684698438657403986439058740935874395813968496846",
+               "549813644389670948567490687546098245665626527788",
+               "64398769586792586795867965624526",
+               "468376458463264536"
+       };
+
+       char testResult[5][4][3][256] = {
+               {
+                       {
+                               "C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F",
+                               "C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F",
+                               "C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F"
+                       },
+                       {
+                               "D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B",
+                               "D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B",
+                               "D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B"
+                       },
+                       {
+                               "E89FCA8099D6B1FFB3A24C435B847A73",
+                               "E89FCA8099D6B1FFB3A24C435B847A73",
+                               "E89FCA8099D6B1FFB3A24C435B847A73"
+                       },
+                       {
+                               "CA253BAC45D205E270",
+                               "CA253BAC45D205E270",
+                               "CA253BAC45D205E270"
+                       }
+               },
+               {
+                       {
+                               "3E9FB188FC11138D49C438ABB98A3846671A4DB257AA62C7929CD55A43E46D88",
+                               "3440BEFCF35DC8773DD631A9C8CCF222009D45E301BBF6432A78E99416CE87D8",
+                               "DDB35281888DF06446772085E3DE849298B4BE0089979260DDC59FACB17AD0BE"
+                       },
+                       {
+                               "233FC5D8B6F005B0966FB313EA0DDFBECF19CBC937445A56",
+                               "29E0CAACB9BCDE4AB219A19AA77E2C9A407C98A18BD56FDF",
+                               "C01326D1C26CE6592FA4E9909D93A85BE005431046661C73"
+                       },
+                       {
+                               "139E51D5AD1EF0E1E74DD9919AE65DB6",
+                               "19415EA1A2522B1B5972F5DCBEEF4E01",
+                               "F0B2B2DCD9821308815ADB01F0A16B76"
+                       },
+                       {
+                               "3124A0F9711A44FC92",
+                               "3BFBAF8D7E569F06CF",
+                               "D20843F00586A715DB"
+                       }
+               },
+               {
+                       {
+                               "E376288A10BD52CB06B42B4582A425907D2DF490EC14B478507BCDE58CE95B02",
+                               "FD82CFAE85B8581F1409EB62D06A98E05C401607619DE1235822E2DEB74737E1",
+                               "24D9411BA4565719BE9FF1A4D91F23B3BF8980A706747077583C8EB84AF63745"
+                       },
+                       {
+                               "FED65CDA5A5C44F619325429C78F464D271807342B10F899",
+                               "E022BBFECF594E22ABC22FA25024B6FD8F61337CBD1F023D",
+                               "3979354BEEB741241F0D219B5521A488F870C849275FF8B9"
+                       },
+                       {
+                               "CE77C8D741B2B1A7E488B94EB32C96FD",
+                               "D0832FF3D4B7BB73AEC7646A3686ABCF",
+                               "09D8A146F559B475A6258D03BC6F8BD3"
+                       },
+                       {
+                               "ECCD39FB9DB605BAB2",
+                               "F239DEDF08B30F6EE4",
+                               "2B62506A295D00687E"
+                       }
+               },
+               {
+                       {
+                               "740A4786C73A7C6B435071A654DA8FCC75BA3299969E327A2ABC7024378CF3AA",
+                               "581B63C58404AEBE49FA5FA4032918813075279E836DFE9BAEDF37D9B21ABEE1",
+                               "D5FCB196868673D1FA9C8A67E6A2449354B292E1A76BA11C416A394116857B29"
+                       },
+                       {
+                               "69AA33D68DDB6A561FB6D6218FAC0E812514782FC6059E46",
+                               "45BB1795CEE5B883232EBCCB672FC9C4803C6B827825FE94",
+                               "C85CC5C6CC6765EC466B8F8AC8DFC91CB916F617873AF187"
+                       },
+                       {
+                               "590BA7DB96359F07DB2F2CE68748425C",
+                               "751A8398D50B4DD24E4681B6D0E880FC",
+                               "F8FD51CBD78990BD5D088ECA798DA0E6"
+                       },
+                       {
+                               "7BB156F74A312B1A8C",
+                               "57A072B4090FF9CF1B",
+                               "DA47A0E70B8D24A043"
+                       }
+               },
+               {
+                       {
+                               "0855A84EAD2176C3D2C3DE4FB868CA2C1B0DF550E187E29808C45594C070FBF4",
+                               "A8420E97462B02158D2CABD1574D072F8D83123CED9BA7CEDD7C2799E168F32D",
+                               "3461DEDF1B4893E182BE36017DEBC6669B15269DFA4435A31EB1A0CE6A845176"
+                       },
+                       {
+                               "15F5DC1EE7C060FEDC9B1B43A20588E7A073A300BEFC4CAD",
+                               "B5E27AC70CCA142857CB807226DC1EA9B31BE81C0FDCD3FB",
+                               "29C1AA8F51A985DC7E530E6EB7AEAC246F2ED097D09851CC"
+                       },
+                       {
+                               "25544813FC2E95AF817E0897D4E22ECD",
+                               "8543EECA1724E179543979F02103C150",
+                               "19603E824A47708D80E29D3A61BAE5EA"
+                       },
+                       {
+                               "07EEB93F202A21B250",
+                               "A7F91FE6CB205564F2",
+                               "3BDACFAE9643C49027"
+                       }
+               }
+       };
+       char testIV[][33] =
+       {
+               "0000000000000000",
+               "0102030405060708",
+               "4041424344454647",
+               "4693867334098764",
+               "6209876098547207"
+       };
+
+       for (int i = 0; i < 5; i++)
+       {
+#ifndef WITH_FIPS
+               ByteString keyData56(testKeys56[i]);
+               CPPUNIT_ASSERT(keyData56.size() == 8);
+               ByteString keyData112(testKeys112[i]);
+               CPPUNIT_ASSERT(keyData112.size() == 16);
+#endif
+               ByteString keyData168(testKeys168[i]);
+               CPPUNIT_ASSERT(keyData168.size() == 24);
+
+#ifndef WITH_FIPS
+               DESKey desKey56(56);
+               CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
+               DESKey desKey112(112);
+               CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
+#endif
+               DESKey desKey168(168);
+               CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));
+
+               ByteString IV(testIV[i]);
+
+               for (int j = 0; j < 4; j++)
+               {
+                       ByteString plainText(testData[j]), shsmPlainText;
+                       ByteString cipherText;
+                       ByteString shsmCipherText, OB;
+
+#ifndef WITH_FIPS
+                       // Test 56-bit key
+                       cipherText = ByteString(testResult[i][j][0]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+
+                       // Test 112-bit key
+                       cipherText = ByteString(testResult[i][j][1]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+#endif
+
+                       // Test 168-bit key
+                       cipherText = ByteString(testResult[i][j][2]);
+
+                       // Now, do the same thing using our DES implementation
+                       shsmCipherText.wipe();
+                       CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(des->encryptFinal(OB));
+                       shsmCipherText += OB;
+
+                       CPPUNIT_ASSERT(shsmCipherText == cipherText);
+
+                       // Check that we can get the plain text
+                       shsmPlainText.wipe();
+                       CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::CFB, IV));
+
+                       CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(des->decryptFinal(OB));
+                       shsmPlainText += OB;
+
+                       CPPUNIT_ASSERT(shsmPlainText == plainText);
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/DESTests.h b/SoftHSMv2/src/lib/crypto/test/DESTests.h
new file mode 100644 (file)
index 0000000..0834462
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DESTests.h
+
+ Contains test cases to test the DES implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DESTESTS_H
+#define _SOFTHSM_V2_DESTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "SymmetricAlgorithm.h"
+
+class DESTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(DESTests);
+       CPPUNIT_TEST(testBlockSize);
+       CPPUNIT_TEST(testCBC);
+       CPPUNIT_TEST(testECB);
+       CPPUNIT_TEST(testOFB);
+       CPPUNIT_TEST(testCFB);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testBlockSize();
+       void testCBC();
+       void testECB();
+       void testOFB();
+       void testCFB();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // DES instance
+       SymmetricAlgorithm* des;
+};
+
+#endif // !_SOFTHSM_V2_DESTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/DHTests.cpp b/SoftHSMv2/src/lib/crypto/test/DHTests.cpp
new file mode 100644 (file)
index 0000000..354cdac
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHTests.cpp
+
+ Contains test cases to test the DH class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <vector>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DHTests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricAlgorithm.h"
+#include "DHParameters.h"
+#include "DHPublicKey.h"
+#include "DHPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DHTests);
+
+void DHTests::setUp()
+{
+       dh = NULL;
+
+       dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+
+       // Check the DH object
+       CPPUNIT_ASSERT(dh != NULL);
+}
+
+void DHTests::tearDown()
+{
+       if (dh != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+       }
+
+       fflush(stdout);
+}
+
+void DHTests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+       keySizes.push_back(1024);
+
+       for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+       {
+               // Generate parameters
+               DHParameters* p;
+               AsymmetricParameters** ap = (AsymmetricParameters**) &p;
+
+               CPPUNIT_ASSERT(dh->generateParameters(ap, (void*) *k));
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(dh->generateKeyPair(&kp, p));
+
+               DHPublicKey* pub = (DHPublicKey*) kp->getPublicKey();
+               DHPrivateKey* priv = (DHPrivateKey*) kp->getPrivateKey();
+
+               CPPUNIT_ASSERT(pub->getBitLength() == *k);
+               CPPUNIT_ASSERT(priv->getBitLength() == *k);
+
+               dh->recycleKeyPair(kp);
+
+               // Generate key-pair with a fixed private value length
+               p->setXBitLength(128);
+               CPPUNIT_ASSERT(dh->generateKeyPair(&kp, p));
+
+               priv = (DHPrivateKey*) kp->getPrivateKey();
+
+               CPPUNIT_ASSERT(priv->getX().bits() == 128);
+
+               dh->recycleParameters(p);
+               dh->recycleKeyPair(kp);
+       }
+}
+
+void DHTests::testSerialisation()
+{
+       // Generate 1024-bit parameters for testing
+       DHParameters* p;
+       AsymmetricParameters** ap = (AsymmetricParameters**) &p;
+
+       CPPUNIT_ASSERT(dh->generateParameters(ap, (void*) 1024));
+
+       // Set a fixed private value length
+       p->setXBitLength(128);
+
+       // Serialise the parameters
+       ByteString serialisedParams = p->serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dP;
+
+       CPPUNIT_ASSERT(dh->reconstructParameters(&dP, serialisedParams));
+
+       CPPUNIT_ASSERT(dP->areOfType(DHParameters::type));
+
+       DHParameters* ddP = (DHParameters*) dP;
+
+       CPPUNIT_ASSERT(p->getP() == ddP->getP());
+       CPPUNIT_ASSERT(p->getG() == ddP->getG());
+       CPPUNIT_ASSERT(p->getXBitLength() == ddP->getXBitLength());
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(dh->generateKeyPair(&kp, dP));
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(dh->reconstructKeyPair(&dKP, serialisedKP));
+
+       // Check the deserialised key-pair
+       DHPrivateKey* privKey = (DHPrivateKey*) kp->getPrivateKey();
+       DHPublicKey* pubKey = (DHPublicKey*) kp->getPublicKey();
+
+       DHPrivateKey* dPrivKey = (DHPrivateKey*) dKP->getPrivateKey();
+       DHPublicKey* dPubKey = (DHPublicKey*) dKP->getPublicKey();
+
+       CPPUNIT_ASSERT(privKey->getP() == dPrivKey->getP());
+       CPPUNIT_ASSERT(privKey->getG() == dPrivKey->getG());
+       CPPUNIT_ASSERT(privKey->getX() == dPrivKey->getX());
+
+       CPPUNIT_ASSERT(pubKey->getP() == dPubKey->getP());
+       CPPUNIT_ASSERT(pubKey->getG() == dPubKey->getG());
+       CPPUNIT_ASSERT(pubKey->getY() == dPubKey->getY());
+
+       dh->recycleParameters(p);
+       dh->recycleParameters(dP);
+       dh->recycleKeyPair(kp);
+       dh->recycleKeyPair(dKP);
+}
+
+void DHTests::testPKCS8()
+{
+       // Generate 1024-bit parameters for testing
+       AsymmetricParameters* p;
+
+       CPPUNIT_ASSERT(dh->generateParameters(&p, (void*) 1024));
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(dh->generateKeyPair(&kp, p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       DHPrivateKey* priv = (DHPrivateKey*) kp->getPrivateKey();
+       CPPUNIT_ASSERT(priv != NULL);
+
+       // Encode and decode the private key
+       ByteString pkcs8 = priv->PKCS8Encode();
+       CPPUNIT_ASSERT(pkcs8.size() != 0);
+
+       DHPrivateKey* dPriv = (DHPrivateKey*) dh->newPrivateKey();
+       CPPUNIT_ASSERT(dPriv != NULL);
+
+       CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
+
+
+       CPPUNIT_ASSERT(priv->getP() == dPriv->getP());
+       CPPUNIT_ASSERT(priv->getG() == dPriv->getG());
+       CPPUNIT_ASSERT(priv->getX() == dPriv->getX());
+
+       dh->recycleParameters(p);
+       dh->recycleKeyPair(kp);
+       dh->recyclePrivateKey(dPriv);
+}
+
+void DHTests::testDerivation()
+{
+       AsymmetricKeyPair* kpa;
+       AsymmetricKeyPair* kpb;
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+       keySizes.push_back(1024);
+
+       for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+       {
+               // Generate parameters
+               AsymmetricParameters* p;
+
+               CPPUNIT_ASSERT(dh->generateParameters(&p, (void*) *k));
+
+               // Generate key-pairs
+               CPPUNIT_ASSERT(dh->generateKeyPair(&kpa, p));
+               CPPUNIT_ASSERT(dh->generateKeyPair(&kpb, p));
+
+               // Derive secrets
+               SymmetricKey* sa;
+               CPPUNIT_ASSERT(dh->deriveKey(&sa, kpb->getPublicKey(), kpa->getPrivateKey()));
+               SymmetricKey* sb;
+               CPPUNIT_ASSERT(dh->deriveKey(&sb, kpa->getPublicKey(), kpb->getPrivateKey()));
+
+               // Must be the same
+               CPPUNIT_ASSERT(sa->getKeyBits() == sb->getKeyBits());
+
+               // Clean up
+               dh->recycleSymmetricKey(sa);
+               dh->recycleSymmetricKey(sb);
+               dh->recycleKeyPair(kpa);
+               dh->recycleKeyPair(kpb);
+               dh->recycleParameters(p);
+       }
+}
+
+void DHTests::testDeriveKnownVector()
+{
+       // TODO
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/test/DHTests.h b/SoftHSMv2/src/lib/crypto/test/DHTests.h
new file mode 100644 (file)
index 0000000..e2a58ac
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DHTests.h
+
+ Contains test cases to test the DH class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DHTESTS_H
+#define _SOFTHSM_V2_DHTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+
+class DHTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(DHTests);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testPKCS8);
+       CPPUNIT_TEST(testDerivation);
+       CPPUNIT_TEST(testDeriveKnownVector);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testKeyGeneration();
+       void testSerialisation();
+       void testPKCS8();
+       void testDerivation();
+       void testDeriveKnownVector();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // DH instance
+       AsymmetricAlgorithm* dh;
+};
+
+#endif // !_SOFTHSM_V2_DHTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/DSATests.cpp b/SoftHSMv2/src/lib/crypto/test/DSATests.cpp
new file mode 100644 (file)
index 0000000..80f2514
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSATests.cpp
+
+ Contains test cases to test the RNG class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <vector>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DSATests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricAlgorithm.h"
+#include "DSAParameters.h"
+#include "DSAPublicKey.h"
+#include "DSAPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DSATests);
+
+void DSATests::setUp()
+{
+       dsa = NULL;
+
+       dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA);
+
+       // Check the DSA object
+       CPPUNIT_ASSERT(dsa != NULL);
+}
+
+void DSATests::tearDown()
+{
+       if (dsa != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa);
+       }
+
+       fflush(stdout);
+}
+
+void DSATests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+#ifndef WITH_FIPS
+       keySizes.push_back(1024);
+       keySizes.push_back(1536);
+#else
+       keySizes.push_back(1024);
+#endif
+#ifndef WITH_BOTAN
+       keySizes.push_back(2048);
+#endif
+
+       for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+       {
+               // Generate parameters
+               DSAParameters* p;
+               AsymmetricParameters** ap = (AsymmetricParameters**) &p;
+
+               CPPUNIT_ASSERT(dsa->generateParameters(ap, (void*) *k));
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(dsa->generateKeyPair(&kp, p));
+
+               DSAPublicKey* pub = (DSAPublicKey*) kp->getPublicKey();
+               DSAPrivateKey* priv = (DSAPrivateKey*) kp->getPrivateKey();
+
+               CPPUNIT_ASSERT(pub->getBitLength() == *k);
+               CPPUNIT_ASSERT(priv->getBitLength() == *k);
+
+               dsa->recycleParameters(p);
+               dsa->recycleKeyPair(kp);
+       }
+}
+
+void DSATests::testSerialisation()
+{
+       // Generate 1024-bit parameters for testing
+       DSAParameters* p;
+       AsymmetricParameters** ap = (AsymmetricParameters**) &p;
+
+       CPPUNIT_ASSERT(dsa->generateParameters(ap, (void*) 1024));
+
+       // Serialise the parameters
+       ByteString serialisedParams = p->serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dP;
+
+       CPPUNIT_ASSERT(dsa->reconstructParameters(&dP, serialisedParams));
+
+       CPPUNIT_ASSERT(dP->areOfType(DSAParameters::type));
+
+       DSAParameters* ddP = (DSAParameters*) dP;
+
+       CPPUNIT_ASSERT(p->getP() == ddP->getP());
+       CPPUNIT_ASSERT(p->getQ() == ddP->getQ());
+       CPPUNIT_ASSERT(p->getG() == ddP->getG());
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(dsa->generateKeyPair(&kp, dP));
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(dsa->reconstructKeyPair(&dKP, serialisedKP));
+
+       // Check the deserialised key-pair
+       DSAPrivateKey* privKey = (DSAPrivateKey*) kp->getPrivateKey();
+       DSAPublicKey* pubKey = (DSAPublicKey*) kp->getPublicKey();
+
+       DSAPrivateKey* dPrivKey = (DSAPrivateKey*) dKP->getPrivateKey();
+       DSAPublicKey* dPubKey = (DSAPublicKey*) dKP->getPublicKey();
+
+       CPPUNIT_ASSERT(privKey->getP() == dPrivKey->getP());
+       CPPUNIT_ASSERT(privKey->getQ() == dPrivKey->getQ());
+       CPPUNIT_ASSERT(privKey->getG() == dPrivKey->getG());
+       CPPUNIT_ASSERT(privKey->getX() == dPrivKey->getX());
+
+       CPPUNIT_ASSERT(pubKey->getP() == dPubKey->getP());
+       CPPUNIT_ASSERT(pubKey->getQ() == dPubKey->getQ());
+       CPPUNIT_ASSERT(pubKey->getG() == dPubKey->getG());
+       CPPUNIT_ASSERT(pubKey->getY() == dPubKey->getY());
+
+       dsa->recycleParameters(p);
+       dsa->recycleParameters(dP);
+       dsa->recycleKeyPair(kp);
+       dsa->recycleKeyPair(dKP);
+}
+
+void DSATests::testPKCS8()
+{
+       // Generate 1024-bit parameters for testing
+       AsymmetricParameters* p;
+
+       CPPUNIT_ASSERT(dsa->generateParameters(&p, (void*) 1024));
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(dsa->generateKeyPair(&kp, p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       DSAPrivateKey* priv = (DSAPrivateKey*) kp->getPrivateKey();
+       CPPUNIT_ASSERT(priv != NULL);
+
+       // Encode and decode the private key
+       ByteString pkcs8 = priv->PKCS8Encode();
+       CPPUNIT_ASSERT(pkcs8.size() != 0);
+
+       DSAPrivateKey* dPriv = (DSAPrivateKey*) dsa->newPrivateKey();
+       CPPUNIT_ASSERT(dPriv != NULL);
+
+       CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
+
+       CPPUNIT_ASSERT(priv->getP() == dPriv->getP());
+       CPPUNIT_ASSERT(priv->getQ() == dPriv->getQ());
+       CPPUNIT_ASSERT(priv->getG() == dPriv->getG());
+       CPPUNIT_ASSERT(priv->getX() == dPriv->getX());
+
+       dsa->recycleParameters(p);
+       dsa->recycleKeyPair(kp);
+       dsa->recyclePrivateKey(dPriv);
+}
+
+void DSATests::testSigningVerifying()
+{
+       AsymmetricKeyPair* kp;
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+#ifndef WITH_FIPS
+       keySizes.push_back(1024);
+       keySizes.push_back(1536);
+#else
+       keySizes.push_back(1024);
+#endif
+#ifndef WITH_BOTAN
+       keySizes.push_back(2048);
+#endif
+
+       // Mechanisms to test
+       std::vector<AsymMech::Type> mechanisms;
+       mechanisms.push_back(AsymMech::DSA_SHA1);
+       mechanisms.push_back(AsymMech::DSA_SHA224);
+       mechanisms.push_back(AsymMech::DSA_SHA256);
+
+       for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+       {
+               // Generate parameters
+               AsymmetricParameters* p;
+
+               CPPUNIT_ASSERT(dsa->generateParameters(&p, (void*) *k));
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(dsa->generateKeyPair(&kp, p));
+
+               // Generate some data to sign
+               ByteString dataToSign;
+
+               RNG* rng = CryptoFactory::i()->getRNG();
+
+               CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567));
+
+               // Test mechanisms that perform internal hashing
+               for (std::vector<AsymMech::Type>::iterator m = mechanisms.begin(); m != mechanisms.end(); m++)
+               {
+                       ByteString blockSignature, singlePartSignature;
+
+                       // Sign the data in blocks
+                       CPPUNIT_ASSERT(dsa->signInit(kp->getPrivateKey(), *m));
+                       CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(0, 134)));
+                       CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(134, 289)));
+                       CPPUNIT_ASSERT(dsa->signUpdate(dataToSign.substr(134 + 289)));
+                       CPPUNIT_ASSERT(dsa->signFinal(blockSignature));
+
+                       // Sign the data in one pass
+                       CPPUNIT_ASSERT(dsa->sign(kp->getPrivateKey(), dataToSign, singlePartSignature, *m));
+
+                       // Now perform multi-pass verification
+                       CPPUNIT_ASSERT(dsa->verifyInit(kp->getPublicKey(), *m));
+                       CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(0, 125)));
+                       CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(125, 247)));
+                       CPPUNIT_ASSERT(dsa->verifyUpdate(dataToSign.substr(125 + 247)));
+                       CPPUNIT_ASSERT(dsa->verifyFinal(blockSignature));
+
+                       // And single-pass verification
+                       CPPUNIT_ASSERT(dsa->verify(kp->getPublicKey(), dataToSign, singlePartSignature, *m));
+               }
+
+               // Test mechanisms that do not perform internal hashing
+               CPPUNIT_ASSERT(rng->generateRandom(dataToSign, *k >= 2048 ? 32 : 20));
+
+               // Sign the data
+               ByteString signature;
+               CPPUNIT_ASSERT(dsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::DSA));
+
+               // Verify the signature
+               CPPUNIT_ASSERT(dsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::DSA));
+
+               dsa->recycleKeyPair(kp);
+               dsa->recycleParameters(p);
+       }
+}
+
+void DSATests::testSignVerifyKnownVector()
+{
+       DSAPublicKey* pubKey1 = (DSAPublicKey*) dsa->newPublicKey();
+       DSAPublicKey* pubKey2 = (DSAPublicKey*) dsa->newPublicKey();
+       DSAPrivateKey* privKey1 = (DSAPrivateKey*) dsa->newPrivateKey();
+       DSAPrivateKey* privKey2 = (DSAPrivateKey*) dsa->newPrivateKey();
+
+       // Reconstruct public and private key #1
+       ByteString p1 = "e0a67598cd1b763bc98c8abb333e5dda0cd3aa0e5e1fb5ba8a7b4eabc10ba338fae06dd4b90fda70d7cf0cb0c638be3341bec0af8a7330a3307ded2299a0ee606df035177a239c34a912c202aa5f83b9c4a7cf0235b5316bfc6efb9a248411258b30b839af172440f32563056cb67a861158ddd90e6a894c72a5bbef9e286c6b";
+       ByteString q1 = "e950511eab424b9a19a2aeb4e159b7844c589c4f";
+       ByteString g1 = "d29d5121b0423c2769ab21843e5a3240ff19cacc792264e3bb6be4f78edd1b15c4dff7f1d905431f0ab16790e1f773b5ce01c804e509066a9919f5195f4abc58189fd9ff987389cb5bedf21b4dab4f8b76a055ffe2770988fe2ec2de11ad92219f0b351869ac24da3d7ba87011a701ce8ee7bfe49486ed4527b7186ca4610a75";
+       ByteString x1 = "d0ec4e50bb290a42e9e355c73d8809345de2e139";
+       ByteString y1 = "25282217f5730501dd8dba3edfcf349aaffec20921128d70fac44110332201bba3f10986140cbb97c726938060473c8ec97b4731db004293b5e730363609df9780f8d883d8c4d41ded6a2f1e1bbbdc979e1b9d6d3c940301f4e978d65b19041fcf1e8b518f5c0576c770fe5a7a485d8329ee2914a2de1b5da4a6128ceab70f79";
+
+       pubKey1->setP(p1);
+       pubKey1->setQ(q1);
+       pubKey1->setG(g1);
+       pubKey1->setY(y1);
+       privKey1->setP(p1);
+       privKey1->setQ(q1);
+       privKey1->setG(g1);
+       privKey1->setX(x1);
+
+       // Test with key #1
+       ByteString data1 = "616263"; // "abc"
+       ByteString goodSignature1 = "636155ac9a4633b4665d179f9e4117df68601f346c540b02d9d4852f89df8cfc99963204f4347704";
+       ByteString badSignature1 = "636155ac9a4633b4665d179f9e4117df68601f346c540b02d9d4852f89df8cfc99963204f4347705";
+
+       // Reconstruct public and private key #2
+       ByteString p2 = "f56c2a7d366e3ebdeaa1891fd2a0d099436438a673fed4d75f594959cffebca7be0fc72e4fe67d91d801cba0693ac4ed9e411b41d19e2fd1699c4390ad27d94c69c0b143f1dc88932cfe2310c886412047bd9b1c7a67f8a25909132627f51a0c866877e672e555342bdf9355347dbd43b47156b2c20bad9d2b071bc2fdcf9757f75c168c5d9fc43131be162a0756d1bdec2ca0eb0e3b018a8b38d3ef2487782aeb9fbf99d8b30499c55e4f61e5c7dcee2a2bb55bd7f75fcdf00e48f2e8356bdb59d86114028f67b8e07b127744778aff1cf1399a4d679d92fde7d941c5c85c5d7bff91ba69f9489d531d1ebfa727cfda651390f8021719fa9f7216ceb177bd75";
+       ByteString q2 = "c24ed361870b61e0d367f008f99f8a1f75525889c89db1b673c45af5867cb467";
+       ByteString g2 = "8dc6cc814cae4a1c05a3e186a6fe27eaba8cdb133fdce14a963a92e809790cba096eaa26140550c129fa2b98c16e84236aa33bf919cd6f587e048c52666576db6e925c6cbe9b9ec5c16020f9a44c9f1c8f7a8e611c1f6ec2513ea6aa0b8d0f72fed73ca37df240db57bbb27431d618697b9e771b0b301d5df05955425061a30dc6d33bb6d2a32bd0a75a0a71d2184f506372abf84a56aeeea8eb693bf29a640345fa1298a16e85421b2208d00068a5a42915f82cf0b858c8fa39d43d704b6927e0b2f916304e86fb6a1b487f07d8139e428bb096c6d67a76ec0b8d4ef274b8a2cf556d279ad267ccef5af477afed029f485b5597739f5d0240f67c2d948a6279";
+       ByteString x2 = "0caf2ef547ec49c4f3a6fe6df4223a174d01f2c115d49a6f73437c29a2a8458c";
+       ByteString y2 = "2828003d7c747199143c370fdd07a2861524514acc57f63f80c38c2087c6b795b62de1c224bf8d1d1424e60ce3f5ae3f76c754a2464af292286d873a7a30b7eacbbc75aafde7191d9157598cdb0b60e0c5aa3f6ebe425500c611957dbf5ed35490714a42811fdcdeb19af2ab30beadff2907931cee7f3b55532cffaeb371f84f01347630eb227a419b1f3f558bc8a509d64a765d8987d493b007c4412c297caf41566e26faee475137ec781a0dc088a26c8804a98c23140e7c936281864b99571ee95c416aa38ceebb41fdbff1eb1d1dc97b63ce1355257627c8b0fd840ddb20ed35be92f08c49aea5613957d7e5c7a6d5a5834b4cb069e0831753ecf65ba02b";
+
+       pubKey2->setP(p2);
+       pubKey2->setQ(q2);
+       pubKey2->setG(g2);
+       pubKey2->setY(y2);
+       privKey2->setP(p2);
+       privKey2->setQ(q2);
+       privKey2->setG(g2);
+       privKey2->setX(x2);
+
+       // Test with key #2
+       ByteString data2 = "616263"; // "abc"
+       ByteString goodSignature2 = "315c875dcd4850e948b8ac42824e9483a32d5ba5abe0681b9b9448d444f2be3c89718d12e54a8d9ed066e4a55f7ed5a2229cd23b9a3cee78f83ed6aa61f6bcb9";
+       ByteString badSignature2 = "315c875dcd4850e948b8ac42824e9483a32d5ba5abe0681b9b9448d444f2be3c89718d12e54a8d9ed066e4a55f7ed5a2229cd23b9a3cee78f83ed6aa61f6bcb8";
+
+       CPPUNIT_ASSERT(dsa->verify(pubKey1, data1, goodSignature1, AsymMech::DSA_SHA1));
+       CPPUNIT_ASSERT(!dsa->verify(pubKey1, data1, badSignature1, AsymMech::DSA_SHA1));
+       CPPUNIT_ASSERT(dsa->verify(pubKey2, data2, goodSignature2, AsymMech::DSA_SHA256));
+       CPPUNIT_ASSERT(!dsa->verify(pubKey2, data2, badSignature2, AsymMech::DSA_SHA256));
+
+       dsa->recyclePublicKey(pubKey1);
+       dsa->recyclePublicKey(pubKey2);
+       dsa->recyclePrivateKey(privKey1);
+       dsa->recyclePrivateKey(privKey2);
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/DSATests.h b/SoftHSMv2/src/lib/crypto/test/DSATests.h
new file mode 100644 (file)
index 0000000..446733a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ DSATests.h
+
+ Contains test cases to test the DSA class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DSATESTS_H
+#define _SOFTHSM_V2_DSATESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+
+class DSATests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(DSATests);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testPKCS8);
+       CPPUNIT_TEST(testSigningVerifying);
+       CPPUNIT_TEST(testSignVerifyKnownVector);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testKeyGeneration();
+       void testSerialisation();
+       void testPKCS8();
+       void testSigningVerifying();
+       void testSignVerifyKnownVector();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // DSA instance
+       AsymmetricAlgorithm* dsa;
+};
+
+#endif // !_SOFTHSM_V2_DSATESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp b/SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp
new file mode 100644 (file)
index 0000000..1646fd8
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECDHTests.cpp
+
+ Contains test cases to test the ECDH class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <vector>
+#include <cppunit/extensions/HelperMacros.h>
+#include "ECDHTests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricAlgorithm.h"
+#ifdef WITH_ECC
+#include "ECParameters.h"
+#include "ECPublicKey.h"
+#include "ECPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ECDHTests);
+
+void ECDHTests::setUp()
+{
+       ecdh = NULL;
+
+       ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH);
+
+       // Check the ECDH object
+       CPPUNIT_ASSERT(ecdh != NULL);
+}
+
+void ECDHTests::tearDown()
+{
+       if (ecdh != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+       }
+
+       fflush(stdout);
+}
+
+void ECDHTests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+
+       // Curves to test
+       std::vector<ByteString> curves;
+       // Add X9.62 prime256v1
+       curves.push_back(ByteString("06082a8648ce3d030107"));
+       // Add secp384r1
+       curves.push_back(ByteString("06052b81040022"));
+
+       for (std::vector<ByteString>::iterator c = curves.begin(); c != curves.end(); c++)
+       {
+               // Set domain parameters
+               ECParameters* p = new ECParameters;
+               p->setEC(*c);
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(ecdh->generateKeyPair(&kp, p));
+
+               ECPublicKey* pub = (ECPublicKey*) kp->getPublicKey();
+               ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
+
+               CPPUNIT_ASSERT(pub->getEC() == *c);
+               CPPUNIT_ASSERT(priv->getEC() == *c);
+
+               ecdh->recycleParameters(p);
+               ecdh->recycleKeyPair(kp);
+       }
+}
+
+void ECDHTests::testSerialisation()
+{
+       // Get prime256v1 domain parameters
+       ECParameters* p = new ECParameters;
+       p->setEC(ByteString("06082a8648ce3d030107"));
+
+       // Serialise the parameters
+       ByteString serialisedParams = p->serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dEC;
+
+       CPPUNIT_ASSERT(ecdh->reconstructParameters(&dEC, serialisedParams));
+
+       CPPUNIT_ASSERT(dEC->areOfType(ECParameters::type));
+
+       ECParameters* ddEC = (ECParameters*) dEC;
+
+       CPPUNIT_ASSERT(p->getEC() == ddEC->getEC());
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(ecdh->generateKeyPair(&kp, dEC));
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(ecdh->reconstructKeyPair(&dKP, serialisedKP));
+
+       // Check the deserialised key-pair
+       ECPrivateKey* privKey = (ECPrivateKey*) kp->getPrivateKey();
+       ECPublicKey* pubKey = (ECPublicKey*) kp->getPublicKey();
+
+       ECPrivateKey* dPrivKey = (ECPrivateKey*) dKP->getPrivateKey();
+       ECPublicKey* dPubKey = (ECPublicKey*) dKP->getPublicKey();
+
+       CPPUNIT_ASSERT(privKey->getEC() == dPrivKey->getEC());
+       CPPUNIT_ASSERT(privKey->getD() == dPrivKey->getD());
+
+       CPPUNIT_ASSERT(pubKey->getEC() == dPubKey->getEC());
+       CPPUNIT_ASSERT(pubKey->getQ() == dPubKey->getQ());
+
+       ecdh->recycleParameters(p);
+       ecdh->recycleParameters(dEC);
+       ecdh->recycleKeyPair(kp);
+       ecdh->recycleKeyPair(dKP);
+}
+
+void ECDHTests::testPKCS8()
+{
+       // Get prime256v1 domain parameters
+       ECParameters* p = new ECParameters;
+       p->setEC(ByteString("06082a8648ce3d030107"));
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(ecdh->generateKeyPair(&kp, p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
+       CPPUNIT_ASSERT(priv != NULL);
+
+       // Encode and decode the private key
+       ByteString pkcs8 = priv->PKCS8Encode();
+       CPPUNIT_ASSERT(pkcs8.size() != 0);
+
+       ECPrivateKey* dPriv = (ECPrivateKey*) ecdh->newPrivateKey();
+       CPPUNIT_ASSERT(dPriv != NULL);
+
+       CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
+
+       CPPUNIT_ASSERT(priv->getEC() == dPriv->getEC());
+       CPPUNIT_ASSERT(priv->getD() == dPriv->getD());
+
+       ecdh->recycleParameters(p);
+       ecdh->recycleKeyPair(kp);
+       ecdh->recyclePrivateKey(dPriv);
+}
+
+void ECDHTests::testDerivation()
+{
+       AsymmetricKeyPair* kpa;
+       AsymmetricKeyPair* kpb;
+       ECParameters* p;
+
+       // Curves to test
+       std::vector<ByteString> curves;
+       // Add X9.62 prime256v1
+       curves.push_back(ByteString("06082a8648ce3d030107"));
+       // Add secp384r1
+       curves.push_back(ByteString("06052b81040022"));
+
+       for (std::vector<ByteString>::iterator c = curves.begin(); c != curves.end(); c++)
+       {
+               // Get parameters
+               p = new ECParameters;
+               CPPUNIT_ASSERT(p != NULL);
+               p->setEC(*c);
+
+               // Generate key-pairs
+               CPPUNIT_ASSERT(ecdh->generateKeyPair(&kpa, p));
+               CPPUNIT_ASSERT(ecdh->generateKeyPair(&kpb, p));
+
+               // Derive secrets
+               SymmetricKey* sa;
+               CPPUNIT_ASSERT(ecdh->deriveKey(&sa, kpb->getPublicKey(), kpa->getPrivateKey()));
+               SymmetricKey* sb;
+               CPPUNIT_ASSERT(ecdh->deriveKey(&sb, kpa->getPublicKey(), kpb->getPrivateKey()));
+
+               // Must be the same
+               CPPUNIT_ASSERT(sa->getKeyBits() == sb->getKeyBits());
+
+               // Clean up
+               ecdh->recycleSymmetricKey(sa);
+               ecdh->recycleSymmetricKey(sb);
+               ecdh->recycleKeyPair(kpa);
+               ecdh->recycleKeyPair(kpb);
+               ecdh->recycleParameters(p);
+       }
+}
+
+void ECDHTests::testDeriveKnownVector()
+{
+       ECPublicKey* pubKeya = (ECPublicKey*) ecdh->newPublicKey();
+       ECPublicKey* pubKeyb = (ECPublicKey*) ecdh->newPublicKey();
+       ECPrivateKey* privKeya = (ECPrivateKey*) ecdh->newPrivateKey();
+       ECPrivateKey* privKeyb = (ECPrivateKey*) ecdh->newPrivateKey();
+
+       // Reconstruct public and private key for Alice
+       ByteString ec = "06082a8648ce3d030107"; // X9.62 prime256v1
+       ByteString da = "c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433";
+       // add 04 (ASN_String) <len+1> 04 (UNCOMPRESSED) in front!
+       ByteString qa = "044104dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3";
+
+       pubKeya->setEC(ec);
+       pubKeya->setQ(qa);
+       privKeya->setEC(ec);
+       privKeya->setD(da);
+
+       // Reconstruct public and private key for Bob
+       ByteString db = "c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53";
+       ByteString qb = "044104d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab";
+
+       pubKeyb->setEC(ec);
+       pubKeyb->setQ(qb);
+       privKeyb->setEC(ec);
+       privKeyb->setD(db);
+
+       // Test
+       ByteString expected = "d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de";
+       SymmetricKey* sa;
+       CPPUNIT_ASSERT(ecdh->deriveKey(&sa, pubKeya, privKeyb));
+       CPPUNIT_ASSERT(sa->getKeyBits() == expected);
+       SymmetricKey* sb;
+       CPPUNIT_ASSERT(ecdh->deriveKey(&sb, pubKeyb, privKeya));
+       CPPUNIT_ASSERT(sb->getKeyBits() == expected);
+
+       ecdh->recyclePublicKey(pubKeya);
+       ecdh->recyclePublicKey(pubKeyb);
+       ecdh->recyclePrivateKey(privKeya);
+       ecdh->recyclePrivateKey(privKeyb);
+       ecdh->recycleSymmetricKey(sa);
+       ecdh->recycleSymmetricKey(sb);
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/test/ECDHTests.h b/SoftHSMv2/src/lib/crypto/test/ECDHTests.h
new file mode 100644 (file)
index 0000000..81cf6d5
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECDHTests.h
+
+ Contains test cases to test the ECDH class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ECDHTESTS_H
+#define _SOFTHSM_V2_ECDHTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+
+class ECDHTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(ECDHTests);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testPKCS8);
+       CPPUNIT_TEST(testDerivation);
+       CPPUNIT_TEST(testDeriveKnownVector);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testKeyGeneration();
+       void testSerialisation();
+       void testPKCS8();
+       void testDerivation();
+       void testDeriveKnownVector();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // ECDH instance
+       AsymmetricAlgorithm* ecdh;
+};
+
+#endif // !_SOFTHSM_V2_ECDHTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp b/SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp
new file mode 100644 (file)
index 0000000..3c29d06
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECDSATests.cpp
+
+ Contains test cases to test the ECDSA class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <utility>
+#include <vector>
+#include <cppunit/extensions/HelperMacros.h>
+#include "ECDSATests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricAlgorithm.h"
+#ifdef WITH_ECC
+#include "ECParameters.h"
+#include "ECPublicKey.h"
+#include "ECPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ECDSATests);
+
+void ECDSATests::setUp()
+{
+       ecdsa = NULL;
+
+       ecdsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
+
+       // Check the ECDSA object
+       CPPUNIT_ASSERT(ecdsa != NULL);
+}
+
+void ECDSATests::tearDown()
+{
+       if (ecdsa != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdsa);
+       }
+
+       fflush(stdout);
+}
+
+void ECDSATests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+
+       // Curves to test
+       std::vector<ByteString> curves;
+       // Add X9.62 prime256v1
+       curves.push_back(ByteString("06082a8648ce3d030107"));
+       // Add secp384r1
+       curves.push_back(ByteString("06052b81040022"));
+       // Add secp521r1
+       curves.push_back(ByteString("06052b81040023"));
+
+       for (std::vector<ByteString>::iterator c = curves.begin(); c != curves.end(); c++)
+       {
+               // Set domain parameters
+               ECParameters* p = new ECParameters;
+               p->setEC(*c);
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
+
+               ECPublicKey* pub = (ECPublicKey*) kp->getPublicKey();
+               ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
+
+               CPPUNIT_ASSERT(pub->getEC() == *c);
+               CPPUNIT_ASSERT(priv->getEC() == *c);
+
+               ecdsa->recycleParameters(p);
+               ecdsa->recycleKeyPair(kp);
+       }
+}
+
+void ECDSATests::testSerialisation()
+{
+       // Get prime256v1 domain parameters
+       ECParameters* p = new ECParameters;
+       p->setEC(ByteString("06082a8648ce3d030107"));
+
+       // Serialise the parameters
+       ByteString serialisedParams = p->serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dEC;
+
+       CPPUNIT_ASSERT(ecdsa->reconstructParameters(&dEC, serialisedParams));
+
+       CPPUNIT_ASSERT(dEC->areOfType(ECParameters::type));
+
+       ECParameters* ddEC = (ECParameters*) dEC;
+
+       CPPUNIT_ASSERT(p->getEC() == ddEC->getEC());
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, dEC));
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(ecdsa->reconstructKeyPair(&dKP, serialisedKP));
+
+       // Check the deserialised key-pair
+       ECPrivateKey* privKey = (ECPrivateKey*) kp->getPrivateKey();
+       ECPublicKey* pubKey = (ECPublicKey*) kp->getPublicKey();
+
+       ECPrivateKey* dPrivKey = (ECPrivateKey*) dKP->getPrivateKey();
+       ECPublicKey* dPubKey = (ECPublicKey*) dKP->getPublicKey();
+
+       CPPUNIT_ASSERT(privKey->getEC() == dPrivKey->getEC());
+       CPPUNIT_ASSERT(privKey->getD() == dPrivKey->getD());
+
+       CPPUNIT_ASSERT(pubKey->getEC() == dPubKey->getEC());
+       CPPUNIT_ASSERT(pubKey->getQ() == dPubKey->getQ());
+
+       ecdsa->recycleParameters(p);
+       ecdsa->recycleParameters(dEC);
+       ecdsa->recycleKeyPair(kp);
+       ecdsa->recycleKeyPair(dKP);
+}
+
+void ECDSATests::testPKCS8()
+{
+       // Get prime256v1 domain parameters
+       ECParameters* p = new ECParameters;
+       p->setEC(ByteString("06082a8648ce3d030107"));
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
+       CPPUNIT_ASSERT(priv != NULL);
+
+       // Encode and decode the private key
+       ByteString pkcs8 = priv->PKCS8Encode();
+       CPPUNIT_ASSERT(pkcs8.size() != 0);
+
+       ECPrivateKey* dPriv = (ECPrivateKey*) ecdsa->newPrivateKey();
+       CPPUNIT_ASSERT(dPriv != NULL);
+
+       CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
+
+       CPPUNIT_ASSERT(priv->getEC() == dPriv->getEC());
+       CPPUNIT_ASSERT(priv->getD() == dPriv->getD());
+
+       ecdsa->recycleParameters(p);
+       ecdsa->recycleKeyPair(kp);
+       ecdsa->recyclePrivateKey(dPriv);
+}
+
+void ECDSATests::testSigningVerifying()
+{
+       AsymmetricKeyPair* kp;
+       ECParameters *p;
+
+       // Curves/Hashes to test
+       std::vector<std::pair<ByteString, HashAlgo::Type> > totest;
+       // Add X9.62 prime256v1
+       totest.push_back(std::make_pair(ByteString("06082a8648ce3d030107"), HashAlgo::SHA256));
+       // Add secp384r1
+       totest.push_back(std::make_pair(ByteString("06052b81040022"), HashAlgo::SHA384));
+       // Add secp521r1
+       totest.push_back(std::make_pair(ByteString("06052b81040023"), HashAlgo::SHA384));
+
+       for (std::vector<std::pair<ByteString, HashAlgo::Type> >::iterator k = totest.begin(); k != totest.end(); k++)
+       {
+               // Get parameters
+               p = new ECParameters;
+               CPPUNIT_ASSERT(p != NULL);
+               p->setEC(k->first);
+               HashAlgorithm *hash;
+               hash = CryptoFactory::i()->getHashAlgorithm(k->second);
+               CPPUNIT_ASSERT(hash != NULL);
+
+               // Generate key-pair
+               CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
+
+               // Generate some data to sign
+               ByteString dataToSign;
+
+               RNG* rng = CryptoFactory::i()->getRNG();
+               CPPUNIT_ASSERT(rng != NULL);
+
+               CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567));
+
+               // Sign the data
+               CPPUNIT_ASSERT(hash->hashInit());
+               CPPUNIT_ASSERT(hash->hashUpdate(dataToSign));
+               ByteString hResult;
+               CPPUNIT_ASSERT(hash->hashFinal(hResult));
+               ByteString sig;
+               CPPUNIT_ASSERT(ecdsa->sign(kp->getPrivateKey(), hResult, sig, AsymMech::ECDSA));
+
+               // And verify it
+               CPPUNIT_ASSERT(ecdsa->verify(kp->getPublicKey(), hResult, sig, AsymMech::ECDSA));
+
+               ecdsa->recycleKeyPair(kp);
+               ecdsa->recycleParameters(p);
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+       }
+}
+
+void ECDSATests::testSignVerifyKnownVector()
+{
+       ECPublicKey* pubKey1 = (ECPublicKey*) ecdsa->newPublicKey();
+       ECPublicKey* pubKey2 = (ECPublicKey*) ecdsa->newPublicKey();
+       ECPrivateKey* privKey1 = (ECPrivateKey*) ecdsa->newPrivateKey();
+       ECPrivateKey* privKey2 = (ECPrivateKey*) ecdsa->newPrivateKey();
+       HashAlgorithm* hash1 = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
+       HashAlgorithm* hash2 = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
+
+       // Reconstruct public and private key #1
+       ByteString ec1 = "06082a8648ce3d030107"; // X9.62 prime256v1
+       ByteString d1 = "dc51d3866a15bacde33d96f992fca99da7e6ef0934e7097559c27f1614c88a7f";
+       // add 04 (ASN_String) <len+1> 04 (UNCOMPRESSED) in front!
+       ByteString q1 = "0441042442a5cc0ecd015fa3ca31dc8e2bbc70bf42d60cbca20085e0822cb04235e9706fc98bd7e50211a4a27102fa3549df79ebcb4bf246b80945cddfe7d509bbfd7d";
+
+       pubKey1->setEC(ec1);
+       pubKey1->setQ(q1);
+       privKey1->setEC(ec1);
+       privKey1->setD(d1);
+       CPPUNIT_ASSERT(hash1 != NULL);
+
+       // Test with key #1
+       ByteString data1 = "616263"; // "abc"
+       ByteString goodSignature1 = "cb28e0999b9c7715fd0a80d8e47a77079716cbbf917dd72e97566ea1c066957c86fa3bb4e26cad5bf90b7f81899256ce7594bb1ea0c89212748bff3b3d5b0315";
+       ByteString badSignature1 = "cb28e0999b9c7715fd0a80d8e47a77079716cbbf917dd72e97566ea1c066957c86fa3bb4e26cad5bf90b7f81899256ce7594bb1ea0c89212748bff3b3d5b0316";
+
+       // Reconstruct public and private key #2
+       ByteString ec2 = "06052b81040022"; // secp384r1
+       ByteString d2 = "0beb646634ba87735d77ae4809a0ebea865535de4c1e1dcb692e84708e81a5af62e528c38b2a81b35309668d73524d9f";
+       // add 04 (ASN_String) <len+1> 04 (UNCOMPRESSED) in front!
+       ByteString q2 = "04610496281bf8dd5e0525ca049c048d345d3082968d10fedf5c5aca0c64e6465a97ea5ce10c9dfec21797415710721f437922447688ba94708eb6e2e4d59f6ab6d7edff9301d249fe49c33096655f5d502fad3d383b91c5e7edaa2b714cc99d5743ca";
+
+       pubKey2->setEC(ec2);
+       pubKey2->setQ(q2);
+       privKey2->setEC(ec2);
+       privKey2->setD(d2);
+       CPPUNIT_ASSERT(hash2 != NULL);
+
+       // Test with key #2
+       ByteString data2 = "616263"; // "abc"
+       ByteString goodSignature2 = "fb017b914e29149432d8bac29a514640b46f53ddab2c69948084e2930f1c8f7e08e07c9c63f2d21a07dcb56a6af56eb3b263a1305e057f984d38726a1b46874109f417bca112674c528262a40a629af1cbb9f516ce0fa7d2ff630863a00e8b9f";
+       ByteString badSignature2 = "fb017b914e29149432d8bac29a514640b46f53ddab2c69948084e2930f1c8f7e08e07c9c63f2d21a07dcb56a6af56eb3b263a1305e057f984d38726a1b46874109f417bca112674c528262a40a629af1cbb9f516ce0fa7d2ff630863a00e8b9e";
+
+       CPPUNIT_ASSERT(hash1->hashInit());
+       CPPUNIT_ASSERT(hash1->hashUpdate(data1));
+       ByteString hResult1;
+       CPPUNIT_ASSERT(hash1->hashFinal(hResult1));
+       CPPUNIT_ASSERT(ecdsa->verify(pubKey1, hResult1, goodSignature1, AsymMech::ECDSA));
+       CPPUNIT_ASSERT(!ecdsa->verify(pubKey1, hResult1, badSignature1, AsymMech::ECDSA));
+       CPPUNIT_ASSERT(hash2->hashInit());
+       CPPUNIT_ASSERT(hash2->hashUpdate(data2));
+       ByteString hResult2;
+       CPPUNIT_ASSERT(hash2->hashFinal(hResult2));
+       CPPUNIT_ASSERT(ecdsa->verify(pubKey2, hResult2, goodSignature2, AsymMech::ECDSA));
+       CPPUNIT_ASSERT(!ecdsa->verify(pubKey2, hResult2, badSignature2, AsymMech::ECDSA));
+
+       ecdsa->recyclePublicKey(pubKey1);
+       ecdsa->recyclePublicKey(pubKey2);
+       ecdsa->recyclePrivateKey(privKey1);
+       ecdsa->recyclePrivateKey(privKey2);
+       CryptoFactory::i()->recycleHashAlgorithm(hash1);
+       CryptoFactory::i()->recycleHashAlgorithm(hash2);
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/test/ECDSATests.h b/SoftHSMv2/src/lib/crypto/test/ECDSATests.h
new file mode 100644 (file)
index 0000000..70b3345
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ECDSATests.h
+
+ Contains test cases to test the ECDSA class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ECDSATESTS_H
+#define _SOFTHSM_V2_ECDSATESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+
+class ECDSATests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(ECDSATests);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testPKCS8);
+       CPPUNIT_TEST(testSigningVerifying);
+       CPPUNIT_TEST(testSignVerifyKnownVector);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testKeyGeneration();
+       void testSerialisation();
+       void testPKCS8();
+       void testSigningVerifying();
+       void testSignVerifyKnownVector();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // ECDSA instance
+       AsymmetricAlgorithm* ecdsa;
+};
+
+#endif // !_SOFTHSM_V2_ECDSATESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp b/SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp
new file mode 100644 (file)
index 0000000..91f6876
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ GOSTTests.cpp
+
+ Contains test cases to test the GOST implementations
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "GOSTTests.h"
+#include "CryptoFactory.h"
+#include <stdio.h>
+#include "AsymmetricAlgorithm.h"
+#include "AsymmetricKeyPair.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "RNG.h"
+#ifdef WITH_GOST
+#include "ECParameters.h"
+#include "GOSTPublicKey.h"
+#include "GOSTPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GOSTTests);
+
+void GOSTTests::setUp()
+{
+       hash = NULL;
+       mac = NULL;
+       gost = NULL;
+       rng = NULL;
+
+       gost = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST);
+
+       // Check the GOST object
+       CPPUNIT_ASSERT(gost != NULL);
+}
+
+void GOSTTests::tearDown()
+{
+       if (hash != NULL)
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+       }
+
+       if (mac != NULL)
+       {
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+       }
+
+       if (gost != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(gost);
+       }
+
+       fflush(stdout);
+}
+
+void GOSTTests::testHash()
+{
+       char testData[4096] = "FE5A773751EAB2F18921C04806D6907444557B4469CDA7C822288E5065DA58F448A27FA0B4C8786853F246B093E3DBFDC332759D7764B6D057895184D9B82E626DF70AEB99B969EA35E5BE4D50C7406EA4A7450AC063933F96F77960EE711A445593119CF69061702CB4797F214FA440C94127E3DCD92F2C71B39D354C6F4284E030DCBFCB91EA5E543E0E3560ECD355091850BA080287BD87B74BB84A8892E0F2172F136D187305179F23EB8296BF1798405BAB52E201F22BCA5B793C5BA6F2CA15F154598EEC73E7E61B405262F6FE5FDC0F9AE0528801C3F965956C79A6C6805EDD0C6515AEA27D1DB9D70A56B0F13A544429C448FB6DB390C0E367EDF997E0B681ADE3846D77D1898F06FB60CB2384015F3749BD1E8163E532529E4D3BB8B200BBE79DA76D4865621FF2E583A1A1F8EBFB7A51B65DC9152B173A7DF91C6943F2FE497CDBC306827146199ADA925DD42B8A48429F5B6E3670AA85A44BDFAB3D273EA6711B996B5C27E04949BE61ED9ECB932F429ADCF31A2E0E9F83FCB1CE6BC0EE81627D1F9D08ECD599F16A1D68B256B002E90A8B4E5830A049ECE9ADF1D50C027EC537DD5412AA1509E91CEF358B2D495D3B37651987F51D9643A5AF2E0EF3D8C02E6023BB76FF8F1EB5CD018FA32BD7886A1A46A7D5CA15E4E0CDB793F0C1986EF4480305801A518B1D4596AAA741C093FC7AD075B637B1B2CC4DA33B6EB6D549001B33E1753C9C4358FB541FDE6541238BD011CD8ACAFB4CFF15B289872956DFBCC732593E838B6300E48ED3455CD101920114640A5B7C1250E419B7D771EC65934F53176BBD7A61A36D6D3D64A1F29C3D41745993636F812930E2936E9ED34E92A3C31239176ED3F78461EE80C54D92CBD9EF9F5746F8069809A38549FC7A8FD99FB350C27230966D6001D3136114A7BDCDEE495B72E4A633845BC88400DEDADC2FA2CD8640049CDB4F8F695C45EACF24FD573E1FB1670F688C9D7706A9AE9EB30E0DFDD54C7F3F3EE6F9BBFBBED6DB6E7C7B979E677DCD8457949DC271BD6ACB445B16247D8DAC1B59D45B8FFBBFDAEA20A5C450E0F93B399AE69887E1C721B0EF86C8CD37FC7514C4F2B70AA1E757DE95DCC3B74C6E18E51D272D433330826435B7CBA6C099558B51E408B1BFE60E876141A74195A00BF914F2536D92170FB43E078D98F784E6F150ED2B16DB5B629EBABF16444639C87A544050E03FB7CCD538DA29C45CE764F68682B48BF8AE5ED43064E833338A88605B1743FEB025D5F5607BB13A2078A99924A2D4818CD582ACDC1556FAEBA70959DE8498F3FCBF85BD269A7DF23A3AD5704908978031667C7BF4A85D1EF42F3ED144670E6EEB5D8213DB43B0B7B43767FD4277EF0EC52B5718A7D187A003DE8E5DFF9C3A3CD520615FB9B52281506E5BB033818E0912980A8BCAA54E21C5630B9E863C83";
+       char testResult[512] = "3EC65819A084AD30712C4B3EB69CE130A8C7221EA3D8A9996D4BA6F298BC39F9";
+
+       // Get a GOST R 34.11-94 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::GOST)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), gostHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(gostHash));
+
+       CPPUNIT_ASSERT(osslHash == gostHash);
+
+       // Now recreate the hash in a single part operation
+       gostHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(gostHash));
+
+       CPPUNIT_ASSERT(osslHash == gostHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+
+void GOSTTests::testHmac()
+{
+       char testData[4096] = "1450414E94B2CEA9E202B8ACC9C358EBA5334C20CF1B7D13E8B79BE63A0A938A340CF710D539262F406787AF7188990C7D75780C265E37750510FA6AAA742D01C753548219C20B1283CCA9D30AA5A8650D0C5EE63FE10268F9CD5996F8DB0158C6FAD147AE41C0E565F6FBC85115E17BB0B448208075D1CF79CF70574098E7116A5C5EFFDB05DCD83E71DB4860B3AEC2612FB9DE1B010229A413055724AB07F4131B04800286D3C4895A158E7B1301F8010E718C76CC69B34C643D2B1EACC00F9CD0DEBC83425256B2524B34D61EBA32FE5F79FE0A1F9360E3CFB4C88CE7CC3C36E969A37827AD5FD79BFAC08CCA1786F30F34ADC605545F04BA96CA4A4E3DF7FEC36E43406E9CD68D708CBAC4C54B2E18E38535BD1A8029FD7393B5462AB688F8146445295E5473B15B26EC129A24C78B7198D558209E827C38426D747FB0D2B04F1EE7B142B7B736EFF4B819B5420F4642E77181617BEC8074109B463F4C53A6F3507A0B4419B2D7CC0B6CF89FAA2CAEAC17BF19E6A94E0BF346D0F77C47EDB29CBD204483E53853401779AEA0998B993E39EA4C5003326C017A5A3BD0C5591D4F822641FAE9DBDF78B15DC5BA326150F89C864774A8DBF6464B259A29C00D9BCC63F61B3B45FF19E6FD0CDA2BE17608488B0E5C6CC5C596F035C8E580C30FC7C6FE2428F3509511B9D7FE77CF53C5B0E8E66BB573B3D467B74B5493A4E8EA49A79B7E2D36A6C0A600C6B13DC617C3FAF927B2CB251279CFF4228254CB6022AE9D97A36894EBCB305B179284E5D2F330266B2B600E248D3C4B8121A8D698183A38BFB5A40C5E85CB08EF0BFB0242E418D11DD648B9B84E072A70D3FBA8A9B0CEE05BFD71AC945543E306824F9A4DCBA05BBE0027B475A020BD764B53AA5A187C089A2DEF8F3A96D38491A61CE5F3DA625F7F4EF38130B0F5DAA14E2236F4CD95FF0C31E7D6C1CC15CDE7D9D4F95326AE721812458D413CD6C758671C9A85D10F7692CE31A600483F6444F45E74C45B7CF886E63D0158E19C0B87BE6CD9FC4B74D72CB004D3BD7ADF60E162F4967E5EF3BCA0AF2DD7ED1DDE4097B5BA250281DB7E46C22A25A49ABDB1B2D148710128DC1F1A18CD0D762A1D2EB5D5D602336EE3F0A0095592E938A79BDEE72CF801015AD5871A8D907298E13F960A1417FDFA87C3FE3DA9490B73B45326C3161D9DE6460E37208665FDC90CF894A0301198F5FAA5A315FC562B2837194662A58DA13065760571172D42306BB57ECCFA578E9C927C211A1F7C1983DE1AE1EAB0A264AFDC18CD56F14E0429E80B0DDE9A5AF527952A7B6ABECFCB64CBDA3C3E7A024FC5CA3B655FAF5A2787FDB22C1DD3160827C886A119FD2833DA87E60F18B6A969916D35F559BCEA40D6E5E53F84FA5C46DD5DD09D0802A21F64F00EA755F95234AF913DBFB380CC370754448E46EDFC7CCC";
+       char testResult[512] = "8D9D660D7BCAB705F14A90CB9A31F7B5206F9936E1B56F2489DA188A90C49CA3";
+
+       // Get an HMAC GOST R34.11-94 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_GOST)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-GOST_R-34.11-94_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult), shsmMac;
+
+       // Now verify the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now verify the MAC in a multiple part operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now recreate the MAC in a single part operation
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now recreate the MAC in a multiple part operation
+       shsmMac.wipe();
+
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Check if bad key is refused
+       osslMac[10] ^= 0x11;
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(!mac->verifyFinal(osslMac));
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+}
+
+void GOSTTests::testHashKnownVector()
+{
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::GOST)) != NULL);
+
+       // Message to hash for test #1
+       ByteString msg = "6d65737361676520646967657374"; // "message digest"
+       ByteString expected = "bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0";
+       ByteString result;
+
+       // Test #1
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(msg));
+       CPPUNIT_ASSERT(hash->hashFinal(result));
+
+       CPPUNIT_ASSERT(result == expected);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+       hash = NULL;
+}
+
+void GOSTTests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+
+       // Set domain parameters
+       ByteString curve = "06072a850302022301";
+       ECParameters* p = new ECParameters;
+       p->setEC(curve);
+
+       // Generate key-pair
+       CPPUNIT_ASSERT(gost->generateKeyPair(&kp, p));
+
+       GOSTPublicKey* pub = (GOSTPublicKey*) kp->getPublicKey();
+       GOSTPrivateKey* priv = (GOSTPrivateKey*) kp->getPrivateKey();
+
+       CPPUNIT_ASSERT(pub->getQ().size() == 64);
+       CPPUNIT_ASSERT(priv->getD().size() == 32);
+
+       gost->recycleParameters(p);
+       gost->recycleKeyPair(kp);
+}
+
+void GOSTTests::testSerialisation()
+{
+       // Get GOST R 34.10-2001 params-A domain parameters
+       ECParameters* p = new ECParameters;
+       p->setEC(ByteString("06072a850302022301"));
+
+       // Serialise the parameters
+       ByteString serialisedParams = p->serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dEC;
+
+       CPPUNIT_ASSERT(gost->reconstructParameters(&dEC, serialisedParams));
+
+       CPPUNIT_ASSERT(dEC->areOfType(ECParameters::type));
+
+       ECParameters* ddEC = (ECParameters*) dEC;
+
+       CPPUNIT_ASSERT(p->getEC() == ddEC->getEC());
+
+       // Generate a key-pair
+       AsymmetricKeyPair* kp;
+
+       CPPUNIT_ASSERT(gost->generateKeyPair(&kp, dEC));
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(gost->reconstructKeyPair(&dKP, serialisedKP));
+
+       // Check the deserialised key-pair
+       GOSTPrivateKey* privKey = (GOSTPrivateKey*) kp->getPrivateKey();
+       GOSTPublicKey* pubKey = (GOSTPublicKey*) kp->getPublicKey();
+
+       GOSTPrivateKey* dPrivKey = (GOSTPrivateKey*) dKP->getPrivateKey();
+       GOSTPublicKey* dPubKey = (GOSTPublicKey*) dKP->getPublicKey();
+
+       CPPUNIT_ASSERT(privKey->getD() == dPrivKey->getD());
+       CPPUNIT_ASSERT(pubKey->getQ() == dPubKey->getQ());
+
+       gost->recycleParameters(p);
+       gost->recycleParameters(dEC);
+       gost->recycleKeyPair(kp);
+       gost->recycleKeyPair(dKP);
+}
+
+void GOSTTests::testSigningVerifying()
+{
+       AsymmetricKeyPair* kp;
+       ECParameters *p;
+       ByteString curve = "06072a850302022301";
+
+       // Get parameters
+       p = new ECParameters;
+       CPPUNIT_ASSERT(p != NULL);
+       p->setEC(curve);
+
+       // Generate key-pair
+       CPPUNIT_ASSERT(gost->generateKeyPair(&kp, p));
+
+       // Generate some data to sign
+       ByteString dataToSign;
+
+       RNG* rng = CryptoFactory::i()->getRNG();
+       CPPUNIT_ASSERT(rng != NULL);
+
+       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567));
+
+       // Sign the data
+       ByteString sig;
+       CPPUNIT_ASSERT(gost->sign(kp->getPrivateKey(), dataToSign, sig, AsymMech::GOST_GOST));
+
+       // And verify it
+       CPPUNIT_ASSERT(gost->verify(kp->getPublicKey(), dataToSign, sig, AsymMech::GOST_GOST));
+
+       gost->recycleKeyPair(kp);
+       gost->recycleParameters(p);
+}
+
+void GOSTTests::testSignVerifyKnownVector()
+{
+       // TODO
+}
+#endif
diff --git a/SoftHSMv2/src/lib/crypto/test/GOSTTests.h b/SoftHSMv2/src/lib/crypto/test/GOSTTests.h
new file mode 100644 (file)
index 0000000..f243392
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ GOSTTests.h
+
+ Contains test cases to test the GOST implementations
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HASHTESTS_H
+#define _SOFTHSM_V2_HASHTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "RNG.h"
+
+class GOSTTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(GOSTTests);
+       CPPUNIT_TEST(testHash);
+       CPPUNIT_TEST(testHmac);
+       CPPUNIT_TEST(testHashKnownVector);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testSigningVerifying);
+       CPPUNIT_TEST(testSignVerifyKnownVector);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testHash();
+       void testHmac();
+       void testHashKnownVector();
+       void testKeyGeneration();
+       void testSerialisation();
+       void testSigningVerifying();
+       void testSignVerifyKnownVector();
+
+       void setUp();
+       void tearDown();
+
+private:
+       HashAlgorithm* hash;
+
+       MacAlgorithm* mac;
+
+       AsymmetricAlgorithm* gost;
+
+       RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_HASHTESTS_H
diff --git a/SoftHSMv2/src/lib/crypto/test/HashTests.cpp b/SoftHSMv2/src/lib/crypto/test/HashTests.cpp
new file mode 100644 (file)
index 0000000..f02adbc
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ HashTests.cpp
+
+ Contains test cases to test the hash implementations
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "HashTests.h"
+#include "CryptoFactory.h"
+#include <stdio.h>
+#include "HashAlgorithm.h"
+#include "RNG.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HashTests);
+
+void HashTests::setUp()
+{
+       hash = NULL;
+       rng = NULL;
+}
+
+void HashTests::tearDown()
+{
+       if (hash != NULL)
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(hash);
+       }
+
+       fflush(stdout);
+}
+
+#ifndef WITH_FIPS
+void HashTests::testMD5()
+{
+       char testData[4096] = "EDB39CC3CB5E8FD23A2182FAE8781F4E8E8534C8FE10BDC7ACDB34C4E22E4B60872E51AD092950771E475FB97B05D6203A0D1B3326D9678E44FB40787D8CF16BD3BBE4D4786F60BD8E9766EF1C30B22301FA8F7232358B3C5BE644342499622A5153B29D2E5F8F509771E8A5DE3B3737D30F2AB035262B8D83EC55F683E9B62BBB31E2E1F5E142A13ACB9701E1DE8752ACD492A943C2DB57CF4035BDA9D0519B86847CF74DB2F43CC23016D88EF44BA422710C00AEBB2ABDDED89D92E4BD132CEB87581644198B0D4AF82F3CE161ED03A4E189BE8276243243817F91159BDE294E61400041537618703754C609709846C3EDAE6922B498D24FDC6B9AE702A034BB3A2C6C230E58EE5759DC84AD0B960B111153F6D619E850E36833A26689B4718719EFF3A407B77B0BAD24A17E29B6A29E9125B4CF0DFFEB8D0B03D533ADA43D1F20CFFE0A067E0F6FFF28510148DD72AE33D8B72227523497B84082B682A480FA3B2FE42AAFF49883DAA4DC6826C9593D38002D73FA7AA91B41E828CC34FF12ECC1452B73709696A440CCDF3E6116DA36CB7A01C9E168C3518304721D2CDBC077F4D4B7E8D1A59F954872862F72AC12CB16E33BED8EC3CFD912E36BBF4DA86E31F5F45BE9294550965C7CBC03518AD7C5637A97F7470EDD6E359E82815230CE03AEE9512939A214D017719E5F6B2487E3B468D50DC8EA41EEE94360E77E0EAA9C27DFE2C28D63B7699406E2E6620FE23F96584EEA04034270A2A44096B70017CC2CB197CE8DA3B1924D8D2E86FB40FF59CCFC78B3A4F543068F08C3406DEF52413F95B2BE2AD5DA1ADBB7D95F2133F61AD5518A1BEA018E3C3C0C154EAE56B0B0F4A8818AE47DC618D138245192D055CE4EF8BD1A75030EABAFD66E45B204BA6B123FF54D78F51B6A7DB9B08BEE93E923F9DE553EC0BE4B8BE222998BC792002005ED66C0218902E7DDF6C6D5043A8A9790E438D5BDE37791CDC0DB6C974638884270D4F379DF845281C5F1F8A20978086A9444779D59423B6CEF8175E0BC2C517FA921EC66BE3F11ECEE078553F610D5B65FD293E37717C0CB323A2760646AD56C77A4B96940CF5AD1154A642043E40788C2D367123399FA6015422F5EFEC851EF558ACD4BC31EF3D3EF912241A586E54B97FAE083EE45FBBBED74BC9E3887795FC2EBC5354ACA358EC509F4AB8B2967488D5E5B77DD44EB72E66694A1F490ADEB2848918531B6FA7216C51CDB507598F1AA0985626482D3546BEF5CA3BB409934D11AECBAD47389F2CBCD85FB4DD1A8A6F4D0C28920671A31FFC14FC00FC51296A6182D5A05B16B33232798F0993C78BCC662932E2F57626D639DD00E39B206C1F8A15A19B5DCA9F8B015611AFA47A10A30527F552A22574E15E3577EAD9C7B89782F82D7082D747B50CEFD38C6F17D6269A696F518EE6EAFE1E1EA96FB4D";
+       char testResult[512] = "7299FE513582D71A3B9EA1E9F45F95FD";
+
+       // Get a MD5 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::MD5)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+#endif
+
+void HashTests::testSHA1()
+{
+       char testData[4096] = "0583243FDEDEBF8C9EA4017808B490A2581A5A06B8C2CCA4F2259B7FABDE4BECA9F80C3EFBFEC436CF5F252568CDF55C7D31002456F6FE711D404F9A274037E8D55EC6C55077E4900EEAF6524C44FBFCC1C5C1C6AF962CE22106610A7C8DE7D725BF924B81EA566B952C8723E0EAFA21EB2C6E6F5528A89FC24C478C0600CB4FD482FAFF8507284C5F1E8AEBA9CDBFB3E71D77B775DD7C09E65049423BBAA70499450AE3B46703A4A44AE281C1F0341EDF0473B079C44E0F9EFB4C3683ED706E480C901A16E77B52030A7E46E31991131AED9C98DCA1850A4BD6F35DBCF5A894A8843EE656EF0DC617D923EB38426855FAA2E77E70CE9A8AC81D0F14259A748F9227F732420CDAE5A1CFEA9B541F0B12ADD5D966EBF66613D7FBAF5FFCAC8D625CFA536DBCA8E54B01B237211656F165A8114CD157E82870BCCE6AE8AF5334105B4E50B0A4E4AE5D0A3CC5CD8FF85F7C4D20D2627694B168CB48DB81B5B78C620C7559B2043C268F5D7351256D41FE892ED8EF6F7B5DD8E193EDCD268C55C209DCD0E827FCF76D6951CEBD0065826FBF044ED5818FEE4ECB99973FDB6826BF92488652E804C40D07D4CE43FCB31481667EE637721B91FD38331A98A6E8969D5B1D0690CFA0B500D72BF2D42AD6471FE064496C91126EFCC46B8CD093BCBB70D21FDE1937A888CA08DF3068A858280ABEAF71608BC9229E8E5EFF1814C4887E3A26782A110F347560DAB6B07DB8D063E8343A3FCD99B34C3C3F649096339CA7D39DA6F7B2E489A9EE6CE01C923D45C50350AC57247838E323F1B2A284606E45D60938A6F492545C5EBA0C7396702C0F4E77F36AC9ECE7ADD32FA4EEF7B38F9FF3F8BFB4E05F1025AAB52FB1B4777A4FC4B881EFA484D04397DE4312B7EE2BCEAD0ABAC0513D9C1819F59996AB5E94D48C098634D9907A4CA41B5A900F7CC299937B089A52C221333BF6B35242CA8D552A9CAA3BB18944D5CCEF69E752FA74A8BA3DD58159BAE375944B26A636457C30C451A58984BD6F028C8CBD3ED893ECD2F1536AFF3A97DB92C0E2FC93B9CC3837FDF56E4E3065D10B15F9A5A8925A5F772E4521CDC885180ACE49D98719BCE6770604C11E6DF090C199A5BBF1D695E1D55E2C9E135E89AB26446F6FED3FBD7DFE58EB75CA61B2D3DA4974908C7183E62FDD79C233387C78EDFF8AAC412EA36AD929808023EF04B8C9B7F980CC3FFD50E7356F51FBDC3DE8551C4F5B283D41E861E5604155E81748BF017268D4FBA8D253CA695300F5FB9A51190B24E2B17653519A3FE500B27DFF90A9FDF8404AFA8FAA1C4F738EB45969846E0A18693C06CA5FE2F2B5F7A33974A9453383E558317468B47DDAEE7A2AB90AA2446155CBF5B6473628C1D6BDA9044D4D96D1E3846AA7A65046C680BB173670FC04E5AC7D8CF41C6F233BD6945C0EA90958E9DBFE67D0EBCD";
+       char testResult[512] = "9A5BD96DC0CD3B0089FBB6BE7D56BEE638431F5A";
+
+       // Get a SHA1 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+
+void HashTests::testSHA224()
+{
+       char testData[4096] = "8F300FA699500CA5E1E22B38EC06B2EADCE7738CF6A55CB241577D53ED68BD017517C83AEB9CD3A25536FE999B7CD61D9E2BA85C39A7D27CE2CAAC8FE7C12FA1B2905DB85ABF230A813C1A72D2BD93BE0C5A79842FE35C5EF4B2E94524FB9594E3CCC63FE2A4E21D91C25DED832FE8BC9788697051C2042094585187394BD0AFD64FB627F3CCB350874FD0D454BF0254A72DD99ED211F68DC15B94A5682B73B89BF533746E8EEC5CCE45DF55466D7026A95A062EFD49FA270751A8D427095D38FB757FD4D1395B5DC7D302D9CF28C2E2D09796B9E0FC2D1F56BDE005FCD266B097822C170981DE2DB5E92582A612019823A3A062E228AB99AD6A0E47C1DEAC0078460252D83FA11253A3EFD374B2B392F0E27079F9FCACBB8EE6320C7A06327335AB34B757057E6C7FEC5004C4F675D2C4ACC6B359CC13D6F9FBE7E12EA7F6FF753CA8FB68059DB06D9804CBE08AAA55E0F20EFB7094695C1BF0D8E504EAD0836C0E6BB491E1691FDEB9ADFE0C92CED19A612DBCA01FF5A515E32B4EC06BDA00482DE721B6A85F00CAB264B34C5F3749D35603D0216C5AA426BBFF15637D1AE7805ACA572337232C27BDFC9D17D5D129242FD883E3C33250BA089EA03BD794C03D8DB9F57F87DC0A30E37F063B9C4C43518DC9F94E7BB18718D1DC79474CFAF60CBCD5CAA8AAA9FF573E26BB8B722C522ACF561FF34A0716FB7C1217050AD6E8323889B47D7551BC7554909651A9BAFCF5F0FEFD100D35B2E06D89C46E572E3EB5A07FEA702DF10BBCD2CAF2F2A62A9BC162F6369D0DBD9A6D6368ECDAFF4246DEE682C2B20EF4D7BBCCABBE0CD44CFBB531F2190E55C1A650B4D16DB2DA0453B23C4F056C1F791336A7266742976653B2E9377F500AAEFA1EA5FEE3469F4A85A484F69FBFFC1C163F78872AFB79231D9E5B4F8EFE2A9E8487BC33E4EC462F9E451BFEB306964D1F02873EEABCAB0F06361DD463398717537C7C255E3DEF1E9EC1567A600CFEB63F822A3C24B3524225A40F0CE948B0284AEF1F9BBE7618D18839725087DD6BFEE15653B981D6F57ED6685388F3B510140F437E93B92583609D4B873BBA3641B2DB56AB26D3DC27A85866D8F66C4A33D82932ECE277387E583BB20A689BE12B597C6199799A3A53B970596355A46F7F94B9D5E07B09B8C47355CE19D7D2EC1F1DA8F382F7C90ABABDED1D82C8BD673C008E16102025B8C8AD33832953B9E28A1C01353C513D55F4E38C0FBC1FE7C1FB6B93D10B464F851BFE26426BC09C599708CA1CA3413BC4B147CD69A761E688E3846949AC3F455CCDC0DDB4FDBC91D880B38C73B7AD4C8633598F4570E3BCBA3C5E785686E38D2926187CDF0479DF5B818EBDDFDA757C31DF009ED234B3C0F2BC1ADC700FD715AFEE46AE5CBAD02ED086912BE45BE2D61097F008E45067C4ADC4FDFE29220E6CF0C6F7F8";
+       char testResult[512] = "A4E71A239CED53E936011DF80B516A07DFF13BB5B05BE43C46C05CCD";
+
+       // Get a SHA224 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+
+void HashTests::testSHA256()
+{
+       char testData[4096] = "C75FF0C53CB345524BF9800FDF53CE448F3369F9CA08C817F8F07AEF0689274527F0AF1EE7FB5AE99B37456765F39880640BF6C5582111753758DF49A9A13B52379DA0C7AE930B03BC57CD819D2EBA0E38AD33D10876608B99A69D0A73F001065276055C4B659F62F77E7232B021BC085A2472293D2D1875028444902AB29D78C9919EC52B33C9F839B1F839C7FF39B68669C925F53AFC865C93D3694E2FD3F29FF0B7773BB412D0FDB1B506A4D501F840D01AE9BF18D7558109B10A6E55CD8CF9A5279D559810A0B08C84C2C8C294AFEC06C6219EB1647A51488BCDDAACE7C652BB0D3F1DC552E4B42BAFF52FD17239F4C08DDDA1BBA97D8D35D3A3DA32D66858B2D320A62AAA7C3909C3A34DCF9DAA69BEC13B7B3EAAEA8A56E2C6DB2507C43BE8990ADC4A281B8BFC6C76FAED50217F109594902FF7E0EDFF5C018B0FC76CACFF84FB9EA97D6D543EDA732089E82FDE3B9D087320014680E5EA2B21B534125806B650F3268DB7951460A9E32F2EEAAF69300E6F0B7F846ECBC2904E93E8D0423FBDCC3E34C5085A97636EA9961B00880BC381E37C3A6E3115256B1A9E1A915A401A8E507F97A09BF3881E852FEA614DF76D709DE6DC0FE54500E0C42132E9ACFFE4A4A98654190FC6C14FC3E5F42CDCCAE0DE05DEF5F6961D7D13DE15376F35142C5846013B7D4A8A6AB363EC7932415C556B83787C86491820AA29C2FE31E39A3D73D710C490D1AF863C4166C2301ECF6967506DCFF6F97CAE63245634153072FE27E9C4B5F90B3C42E4BDB4FB0E85A548CDE2D3B480ABFB1ED6F054017B120E41529909AC055A9F5A29E25D0E5D1A8E8550B9C85C300BBAAE030B22BB646B1FD3A90FA1C242A26071423B3E239EF65BE8B347663B6BF63436AFFD311D10FD24C8E8D05CA99A808C41E6C9C7B283FE5FE9E311642349D2799B6D0CACD5826CC6CC5DDA22FB8BBDD6C66BB722697E4558A75B6D24FDD55631C17FCB591CA3CBA180CEC241B0555A91DF4D47A648A7D901B02C1AB557C4E1CF33E277AFE008D586857203FD6CE695C8EDD446F74056B173D6A0B07A2A58B39366B58BB76AF96DF9C37A5A5E1F8419163CEAA304D451DC38B8F142C422FB475869667D55D88F7C2624FC0B29A958BB4A44C6B0439542AAB02319D46B7E482149DC9A7C7BEBE651C7E8404140601CDB3742F58B6EEDA137FA083BA9D297F91B41B34C3535230841F18B672ED0FD817B7E4E3CD1FC018CDA63C21C3C3ED68228DF85B8C26572D1B14EF10D5D0BAF6F3ED4B9A8C3DFEB4EDEA00CE2DB5903D510432BCBA791C1BBDD2770F2616AF855941E1BD710CEE4F17C4C7A9E283B12DE901A88D634E4ADE69ED529328D64F8069033A6B4DA5D8E0E1C0150DB862AAD54F2827B41CE1F21E3F890033FD46E438615DDC527D6D1260BDB79478D6A0BE2B58174648A2387E3AE";
+       char testResult[512] = "3902802C215A5271439FE3E81AC7F21DA55545F71193A8DA8BEB0EAC8046A43B";
+
+       // Get a SHA256 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+
+void HashTests::testSHA384()
+{
+       char testData[4096] = "11FCD8770F582C2D9C860D1EB4FDBFE40C551C6F3AF41A2540A39BA3A121BFEF995F1727A8703C29D0A44EB85B339F27955E1C679796A72980BB1D1BEF4D51A73174A983D36CDAD56BC1EEBA5DDD642094996531EEC94DE2FB6E0ED4F23BCB2F1D0B25505EB16306473DA17F809BD994FD9A737D29819BCCF94CA225D2EBB9D89DDA6E03E80A9DE87E44B72EFD397F9F344122B6591CED9BFDE8C0C42D8C17223A93F33B7D569291F91B619297F233C1454A168AAE126E89B0ED32B0B69AB095A1BB24BB7F1AAF8EE0BDBB43025EF3339F96C9EA352E78BA0661DE896E8F4DFAA7EF623F2B5305AD338448C5FCBDD6CC1F1222ED1D8F4C634B82591F8906DA8DDA9A0FFB0F1499B5BD08239F7EB3A02ACEC60FB76754D0AC5077C3B733D346F0BDE654CD612F60E2284115297A1557679901A911C2AC7323DA2FF3CD57895D7D181AD43AB7068609CE046B96B445EA08CDF50C40DFAFBA9F7082707A813B9C8E4E9D7F0230D5AFE40174693512DE96E3FAB1C8F6548880823645A0AD811694B293F788D0D523EBD81851594733EF45FC763B956044E29B29C195BDB317FBF97F41C601A2873C25557C3149F648424380FE79E4DC407A9CECD8F14B843C642FD9921F12786C8A1C6F8514C99672038693C5CF1FBE91F903E4ABC9E55B967B2F72FDF1A2EC09C14C94C001BAC47A0C36E9E6F34431381069CFD64D85F11285391A4DC7419B2EE8062F344538413E757EC258192B90F2CCC1186AB9A4ED5CE1290644CDEDAF03A4BF3E94B9F9D132ED159CE03586C5A69EF0A471146378BCCE799A3CD8D627B688BB28C9288F44D1218BC34A05BEAA398371ADC60CA8A2557AB69BE7B737F84BFFA93A1E1115F498600F52144E0D61055A2FC0CD45E20962CB2FF475896D733C74C2E95986389ED74B1497A35E73FEE0F36270CC65D76C1FE27A35E8F1FA0C5CA7F2C6003E21BD6677502CE268EB55B16DA863FA291AA111F338F10592AF86DFC297718365C04839748195E20A64BF42020846A46C94F1728549B8310A7FBCBA2C1441B033639CE52B6DBDA69F6ACC57F2DE6BAC57755734AFE4B77869C4D9B0DC56B115476A86A82F816CB148CDFD2B1DCCBEFCD4559B59AA88C6429F4A9EBB43B641144752A5E6F8BE1B739AA69FEBCB8D7439E5D917CA759982146E627FF81E80CEBC37BE0CF2A6C12A3E84A389FFD25013C491AE90A395D4DBCA81340E86848217AC426603CCAC981B5ED701CE9AB2851DC5F2ED72484FE99767C0FDB6F122B0C67926A637B57EC4F047804BC3A9BD55CBD78B83154BC27B6F8A66085EF02A206F329F3B1531ED657C75E29DF4276070AE5054F484A12990A9DD13C112FB6D3D57AE42E6A048870FDAABA48F73E03344C0E13832BAFCA2AF81AF19E5C28983F7BAAA5135803E78FBDDF7FB53C9B9B709274F05C774C77F0B84";
+       char testResult[512] = "753659D55E4198325A3FED0A35761EC45038E8963B7525BF00D5A6A5D904DD9FA3FC80AB020185E08B14992ECC36A744";
+
+       // Get a SHA384 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
+
+void HashTests::testSHA512()
+{
+       char testData[4096] = "B9D5BD978E1B4A0268331AE4F0C4494EBA71125ED75B9B4244407271A29D93BF5BA0D6641EBF7A210A0905B5EBE675F7B900B89542D0DA6A3952DF9DC5430ECE31F4A5834CCF132724963A088DE43966DC9F46011F2AD458E8FCDBA18F6D183235687A6145401E9FA2EDF60F47F3835D953B5856B1F8308457D9CEC29246DC51F5B42BD5DE38BD89945667579C05756D1C47BB58C2C3D049C58C014C1F6D962BF5EBA1D273F5A7FD6D9291E293CD30B8D8B489E79E54A7A11953EAF4FB6AC7F99910ECE05B511E098B6AD33A599F5A8FA43692FDD9F2A26F316427A2ED1F231E328864CDF9BA2879E0A711F48038E653520C74B7EEA8858F17AC332B87EF4C70A838263C8B17B373161A5A15293D1A7991F0EEAAE0BB69C95DEC22A1CD6808122489703770B5E276735F9D149067A7F3E6A7D10A790253C81778BB79C06D1F98A2CA9C2E8C4BAC0A96F0F9736B85E7BB4F090C5BEB25F087AC037517A9599D94E072D03D9C48665DD17649E001E45966AB8F2C7D24E38AE4F0519F056B034E0ED2CA133F108105BE4823758543791225144AB0B9609F0F861B69EEA8707D6DB9046910F28C6F8E1D47F59DFE9B59F81242FCBE5A71669B90F7B4050E517CF6D3F2FB8759FB7300F12C786D36183FA64692F379D030D0EA90859D9D8E00F27500B41FD716E325E695E3D8EBB40A4E32AFA75F6F21013C8A3261E9C18291DC99142FFF91EAB6C2B55FF5DE03B1DCC88C79635B96F13B66CE6E26A1D5F6154F3C6E5F22AF4B0334FD4521AE57B6B13E2D3B777AF66742635740ED4FF5FC752B908A079A6BBE8499344096549E6FC6FEDBE57AAF2992E7CBB19931F43360415C39D65D2A92775C78DE97C712022460E48651EBDDB9E0527C7EE59F6C817499100C11E884633DC66EF85B176D7A529894CA8F364F559D97DC7CF1769813FB36F8F738E77354C14A560CB98DF92BB5BB16A5A3EDFB75CB78A718C070BE5D37A6F742F88B51BC633FA9E309311BCA908F4D5EE381FB593B7A53E4CE3A529160A2965D0C4CEDC6548D036A1A4FE4576DA9D35E0CDDE9567E792D5C77EFAC17E531F402E0BE99957A7D378E90C009F3231FEE6E3898B5D2C4291EAD396CA748AB0A39469B921BDC5F8066AB7F0D28EE0C502EBC95C2A39DB4241886736F17DE1F33BD384EFDEA951BF775A0D41A499E85D0488016D7A281A9F7C715EBB7CD6AFBA59C1A93A5AEA66D71C3058C5A293141EE4D2C3E65853EFBEFC55912F5C08B9990A66C313F3199C0769CDCA711E877766ECA773EF2FDBC0656B8427CA6442062D911B13F1C2E92D3F0C608B1D8F12914953720021D5648364F953F93CC49946E44FBAF154A2FE3A8055922F784FF9B56D5FAC35B65266A248794101C12750DB8C107D048E551E52EB3952CFA26345B4E21652F5F3B8F85DE04AF9731B75C79DDBD6FE1A5";
+       char testResult[512] = "E1483A8525CE39705D14D60D8B19BD89087AED5FE6D8913AF8FC3F6F4EA2C1BB5957E205294B1EFAF20AE5EE39A9522F38B4514C3C15ED70BCBBD5821E385F95";
+
+       // Get a SHA512 hash instance
+       CPPUNIT_ASSERT((hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512)) != NULL);
+
+       ByteString b(testData);
+       ByteString osslHash(testResult), shsmHash;
+
+       // Now recreate the hash using our implementation in a single operation
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       // Now recreate the hash in a multiple part operation
+       shsmHash.wipe();
+
+       CPPUNIT_ASSERT(hash->hashInit());
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(hash->hashUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(hash->hashFinal(shsmHash));
+
+       CPPUNIT_ASSERT(osslHash == shsmHash);
+
+       CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+       hash = NULL;
+       rng = NULL;
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/HashTests.h b/SoftHSMv2/src/lib/crypto/test/HashTests.h
new file mode 100644 (file)
index 0000000..dd6566d
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ HashTests.h
+
+ Contains test cases to test the hash implementations
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HASHTESTS_H
+#define _SOFTHSM_V2_HASHTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "HashAlgorithm.h"
+#include "RNG.h"
+
+class HashTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(HashTests);
+#ifndef WITH_FIPS
+       CPPUNIT_TEST(testMD5);
+#endif
+       CPPUNIT_TEST(testSHA1);
+       CPPUNIT_TEST(testSHA224);
+       CPPUNIT_TEST(testSHA256);
+       CPPUNIT_TEST(testSHA384);
+       CPPUNIT_TEST(testSHA512);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+#ifndef WITH_FIPS
+       void testMD5();
+#endif
+       void testSHA1();
+       void testSHA224();
+       void testSHA256();
+       void testSHA384();
+       void testSHA512();
+
+       void setUp();
+       void tearDown();
+
+private:
+       HashAlgorithm* hash;
+
+       RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_HASHTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/MacTests.cpp b/SoftHSMv2/src/lib/crypto/test/MacTests.cpp
new file mode 100644 (file)
index 0000000..8a3db1e
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MacTests.cpp
+
+ Contains test cases to test the MAC implementations
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "MacTests.h"
+#include "CryptoFactory.h"
+#include <stdio.h>
+#include "MacAlgorithm.h"
+#include "RNG.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MacTests);
+
+void MacTests::setUp()
+{
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::tearDown()
+{
+       if (mac != NULL)
+       {
+               CryptoFactory::i()->recycleMacAlgorithm(mac);
+       }
+
+       fflush(stdout);
+}
+
+#ifndef WITH_FIPS
+void MacTests::testHMACMD5()
+{
+       char testData[4096] = "B64CCFF0DC038F4B4B6C77677B1E89774028CFB6F94EE920ABFABC8C389F7DE287D558664FD05836E854458940A486A367C9B771A7938BE7DFFF2C695BB99CB96F946707FB405A0FA94116FC4002FAD47F813C4DAF6F39B579A2C1E607AF0F80E55FC6742ABB46CF25EFBAEF820DACAE925532E0F2AAAD64D23D0E5682DC38FA47F230EAA299C4D87EB76D45D4B4A08BB47AC873A428708F9D236CF9B11831BC713DB5C8F58A4A4DD228B7A370154CCDB92420B01D0B4141B2CBF05E51D364F7A4D7EE20F1299A697AEAE7341EB6C2F5C458D8AA9A33CE6B2C87B42A9C8EABB3A3311E3828935B8743604895A37D0E9717266872B51CBAB50E9399A0E54457F88DB022CD1859D704FE07C2B530BE14A11072133A9D3A8CD94FCA2B22A320EA08D0292DEADAC4BF705B2CDF71CDC13EC72918F2BD8697BA42AA0AAD62E2D549AC639095EFD2EF606414207CD3770A14FA14AAD7EED197A1A61EBF1FCA89CFE2B69E709C98F4299CF6E1DCF34A98F3C89C6357B5DCDCB335C98EA8DBBA64700EFF9B79CCB875FA49C0C8FA8AA98D6B7B83C3818C4078A8433EEEC71423D9B476029C190ECF1552CF59E1BB2ACDB08663FA792D806E5FF5A6D3E4E09C3F6276663A09D5730A9AAB456D4863F2EDEFEF156A7809AA16D3202AA03C64359BAC628EA1D9ABE2D99999C2891ED49C6081DEA6907C93C5873B4D7880DE271D6016075AFF330FDF221790258A99564F1B51B979DE7997F5FD6676F679B4B14222753547C06960ADCC287EDC29E627FB88BD0E73EBC4E631A58DCA425FADFFEE9DBA177EC182CABA803EEE16636599A88C39A828A5FB206F6DDFD6023F560A421FF3D93B6C4A2A27B78283280C2FD5D249C35270EAE8F8947FA07189BB3A03184C1D8DDB12038184C467EE7DA6CD62F1775F316BE3C2FAB947D49DA19B480E8E4CB4C7818D7769351107386311E5EE411DAC5136869C147DA8E782FA60ED69B13C2DE18CF11FD75CE5F8F16993A026FC3441EE3B23DD6002B8F015E5CC336B5559A427864338C098F4857AA40399916614E061BB176AE4457CA72625A37F08F179A14C39B065CF3283E9425355B6504784C0F4FC1D7932F5C14B43A9CE3604935DE695CDB60B1ED58BD71AB540EEDDF9337B0743D8E624E1A932A69FB1FCA21CFE7F6D2FFDA78F2B8D5BCE01C59BC0A3981BB3BBECF345F43ACD571432B742F80491B490FD71F947480FF9D215EC21237F5AF28C31608DA7A6230CAD24EA799506C8C0B1298E9FD09DA496C6B63710920CC0DC14C00944A7D9B9B751D741A828AB35A5926D3653D45531A4D233DE198439D1946633FF6B91DF0744073CC6E3EC3B177414D8ED2AF30515D8688914667F507667776634A2A11BB68F65B363BD56E8CCF957EB4BB0147862D4C17268AFCE5685C8346E1917B8E8618D3888355CE401AAC5D2DF";
+       char testResult[512] = "1026862877813E17E4371095271E1B56";
+
+       // Get a HMAC-MD5 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_MD5)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-MD5_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult), shsmMac;
+
+       // Now recreate the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now recreate the MAC in a multiple part operation
+       shsmMac.wipe();
+
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+#endif
+
+void MacTests::testHMACSHA1()
+{
+       char testData[4096] = "EA9E200DE69522895F516F1380536406D205D72B31ACB902CC582B12696579826B5AF47892C4831D8AEBBAE039D87F82096364782B49E2E896AB8077E773AB61E05A8223BF17CBF37AB1BDDA70C9B10D9943AF4109571ECFB029156889249B309EC45A34E2D701F1F4093610A7064B69E7FAE5FB39E39EEF3CAA9D64E50DA8822DF4C8DFA064B165ECA4C9CD2A6AF1A251A1F5D4004123B67A7CC3FAB7462AD43535018479BDFD24A2C4A1C4271F907E40E2057A6271BB2BC9740F753CA3692E7ACACE547E64B9FAE79A96DF3DDFCDA7FDCCC7612E41B0B9BBFA3BDE2102F322E8EC42DA2679531782920FD2E7385F6AC887D578B9D844F6A7288EDF613F3663EB538DBFF14EA29AC8D2F58C703303CD370F55BAF02532A0BCB2F80673F6D84B04A5C3EF9E05B640B4CFFD903272089B9960B54197CB5D10C23BAFEA72EFF79C65E0EABEC628EEB5850AC4A23DC80E857EBA5EC5EDB9DD0A5F391B7F8BD354EC976881C157BD5735AD894F020164A9DF214150C5788BC1CF73C15437DBF21D791C75074DF4B51B5C0ABDC79063AB7B7CEDEDC6412F9FB1F6CA171BE6814E033F32CF1F08236A3DD657DB96CCF7A35434C4D0ACFCA81546B4138A6EF6987A874111946010F78074E69BA83E3F395D1C239A122B259F48140E4B80157738A5D443E1762C55EBB67791D5297B3E900B0B53CA7433FB61D2D03C3B34772C5DF77711437003C6DFF4B03DC0B713491F526F9AE3260F903EF9A1BED641E1B262103D395ACAC3FE6F6F1436F0CB3A13AC69C60101EC394DAFFCAD8EED23893C4BC30485FC68854447A9930C0F4FB9AC5B72EF6512278F09F5A024C7CF5C5617461751CE193E54051AE93DF136725642E1DB98842BAA8B8F6231181F0BAA8393FC2EDB7CF0832BA1FDB76A46C8059732B7492711AD1A12BA584D49885E263789E27664B3893EF2DE5C010C093DE1A735D806E4D48C36A0995EADF011FB50D0CA97AFF26B4698524B9F75386897940434A0A38EAF513845BF0F024014001180C651F76B9E0ECA6499F177A1079395C1785B856D5762550EAD2B47B15AF0A6BFBB1B597E72B9E5E6F61769C27AFC29E4D8A523C89D1D2E5E59B57DE89BE04BDC1DCDA0476A157BCB4DA2F7AC0CAF9351772652E2E5B6261501BDF42C23EA9726CB6C258EE9511684CFEECA1C0598D372808002E250EDD4019F85630FD499C35016B8A99C6BF78E69053B4AE7BE6B84009B505594603B363037212DAFCC669F7482995C74A7CC225245DC2E7D4CACC8A59F67513E1D788F0218DA902F440CD2FEB6C2A90A653B0C2DBE45CC67B47863C1090F3F41AFEA9C53CE5C61A7E6B7212EE3BBE67ED91EB1BA006A931055512046779935F84D7CA306C7F9F3894F91F51EFF6005F5A8BD9DD8828BCEA1C4CC6E5F22CE7F14C0A942243C1205FD7697F09C333AE0B263";
+       char testResult[512] = "C2FFE4BF83A6FE299CA4A187157F2442EC1527CE";
+
+       // Get a HMAC-SHA1 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_SHA1)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-SHA1_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult), shsmMac;
+
+       // Now verify the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now recreate the MAC in a multiple part operation
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now recreate a wrong MAC
+       b[5] ^= 0x28;
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac != shsmMac);
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testHMACSHA224()
+{
+       char testData[4096] = "83E369A9F34D645B7E1F2F7BB676A4DFD36C411D5472A9AC6F3945EF5C9A561BB040C38F2F321C582882820C7F44D48CDC5BB84F41818F4AEB226F63078CE131481D26F26C61EE52BD1BFB60EDEDE1E03A8656E87D5662EE0C0AE085E56E488325512467DAC43E99484A16FA419D6704922C1ADE06F7D1188DBEC88384CDBFDCD2E74787AE247A8027EF60383B3B0A7D0D3ADA95BB3AA5F0821AF050A9709C75673F3926CF9AE029158D684F470DE3EE6B00BBC90F85CD6E634E86B67E4D8EB4251B472B02D167790C6E6C38BA9FE39880544EA66EB4C0BFF8AFEB9AFC40ADC24DF191744482F70793CB4A802CF1AB58562CC26D1CAA2E80375BA45507C3E9F7D99223E0E7FE93CAC58B7B0C69231162D2D7DA75EEFD59452642CDC5AA4A118B6D4AD00E8368A44988201C6286CAA8612BCFFF714855DE1E053AFD2EEED9737459540E45AEAB26999C0951228716AF02F0D35264E3411B03D222F331A4695D6DF4E9EE35D5B1015FF0BE46081D7CEC9137824217A711F015639BE76223845F1C2A25A10D29B637C5124CF50AB0CAA1E33D75843D00EAE69C3A189D463377731C3197BF44523936C4F84F143759E3D58891F7B3B51C858EE29BC1DF214AF09C93148172E842A7FC0078D4E106324AAF8862B845F290FE831037B2EFEF2528DF070DD7B1ACD67762CF1071B96FB95C5AA14F7AE13103AF45A1CF3C42C5D53CB5B954F97BA223E70E0098E224BEF8F5430D027B510DFBBC35EE5F9170E4A43BDDFCBAE8B82240DB870B6C7C7E21E21234EFA62F1582A9D150CCE1B8822BD77ED8288B20883AAEEB5BDF9D0EBB8D3FF47DD51B99E9BDB8B8A87D0536CC25D4939ECB13F7B4F7DF5F0BE8231CF3F53CE52D16A29825739B26BA4082975583967180F787ECF98AD956A9CE53759E20960752938C142DF80E57DDCA236A1F596031942016442002683865EDB210073797547D83CE77D3D6C39E2B9034E685BD28D365992E821BECAFC6DF2B60EAE9777FEE7879B176CC602501BA0B0BCB434DFA5517F8D6172647364F235B3C9BA0B1B90FE0FD67CF6650C2D8D2BC08D127DF0AB887F69CDD81D03B4CC7F44A4362C90BB38556D081E51EABD9CA3AA6C877C42FD1B001C030D0B281590696B5BB9C6A78CBE356F7AC72F525300FD13E24755294712DDF48D1AD19F844120306DC99D8CC18516A23BD022CF9DC9CACC168ADDE1C15337F15B3FBEDE4BFA498F2F963E14B7E66CD737A5485227BA1BAA7668D97C58DCE40EE7A843A5E6EB591FF91D6A6292C8A3E95A0B23C1F0B8815BE526EE7C49B5153264BC1207013EA85E9DA37F19BD50DDC9F0A5B9AB4FCFFAD2840B5A8856882E8DF95362DCA13C15328137A2A8318884FCF4D05236CEE9985DB1BA873A9AF5B33E317FA2C0CB94E7C18E46744A374C19D8C9B2788FE50C9E4D237D290555E1077";
+       char testResult[512] = "4B089658FF932CA07BF7C42E6EC46BFF560BCAF295826D9D3C0BAE1C";
+
+       // Get a HMAC-SHA224 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_SHA224)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-SHA224_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult), shsmMac;
+
+       // Now recreate the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now verify the MAC in a multiple part operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now don't verify a MAC with different input
+       b[600] ^= 0xff;
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(!mac->verifyFinal(osslMac));
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testHMACSHA256()
+{
+       char testData[4096] = "FF7E669D7764FABF6E3550E192E660DF1EE237B49F9473D757DEFA1400534F57C81E8B0E99458F74E6F57A5BB71A50D1EF61EDB3B3FB4BCA57896DFBA50C6C55B04D4C8C804DB8EB2A273E25F49AE2742D2AE430BE9A3A07715AF6816E818B63BB1FF8C876A921CF931F693E624CDAD4B54F3ABBEE4A09BF39E0FE3A313B20CD3A36B0EBD677D9D4D7C576B5EA244CF0436110D9D66110C95BE187D6EDA1E81A4456231BE32A1B5F4CDC02B2DA679322AEBAE0B795763888F07F0222ADBF824F31AEC7B80625DC36DA1F0C3DD20C6E8F79A7FA2D286119894E611EE550364428723E9C33A573F18D02F9DC90ED215EF08C95DB1CED68DA864732BC9A56B8B191815BCC12075641E3E87F46EFD3726BC1D6F47AF7BC573C554279C041C7FD5E924093241855507EE2A837E2CE62E7A9898712EDF593217B6425B3EB855D53D31F38E5A0736E34844AFCAD58A15B06D357697DC921C2FCA77091BFC207B0B4F1FA94F923B05817211462104287B43CA72986D9E6E393C9A075C267B2C1706CAD136E9F549A83E58315DE8D0B67852006EFE8B6E0773519FE6DB316EA596E1998B79C19152AADDDF8E025E7EDCB16B5CCBA2C9F990605A6969D3C667D6EDA1DA5AFF476661349712CD73F707BB0FD6F8BF0C13A90DE9C1C5CE9FB696C22849C1205C8435C818E2EE03F2235B502E0C24068B8687AF9ED065910535072DABB83F651FC60E005BEF909F6EE308B37E43DA01366C062168007D733D5EA4A610D1307BA087E8F883864140BBB02E523997A0D83E9BF289B8EC9F83F57FF553485409B0D82E77F32BD2D06A130103B9F3915730EE8BC3FB099B74AE8B32C478A83D0BAD2281C279D6B802F42A80E179F4ABB69AD485BBAE348C6F774285870F53699500CEC045B9521CF22826FAFFBC4EABE9D856B28DDBC6D2A0F318AE9475E82DE2CA6704B743397EFE45F825019B58D9E671181512D780B1BA34D059BFBF8B9B232E337335C1045682635CEF8D3CB1C744D3A7791F5DB323EF8DE768C63931266EAB0DFACAB0F99BC9C5DA234FE48ECDB23A5FDA2E92EC10AF7476B07C4BB85BDD0600B49F41585F9E0DB2B276BBE0FA7C5792B65012B6564561E4814E8D1EE706935A45F969C9AA110A630E354C7243E21436A180046605FE5D31008045A5C4AB4FF5C23585D77D6C839875CC2E960436A3D90F9664D5522EAB08867B95F9641DF0C81D59DCA8ECE8709A3F521532041BDCF7A7535F940BD3569FD2145A1B34E955E04F66E0CA809BA3FA6A347FD0CB69DADBA93DC03CDF547A96CD3159ACA61EFE20F9A566316BB9C746EB851CE51F04823667CDA0D898253BB10C1C5220B2C30461A49C5FF0DEC38264786C6125720B3768629ADABCF694E01795F618FBD0ADE5C91CB5A981BBA581A9664F51DF758D7300E081E57CE20C8A7210BC3558AD240B7";
+       char testResult[512] = "90A49F8EB80D8ED405EFC8D658FCB9102314598939DCAA090756668056B0228A";
+
+       // Get a HMAC-SHA256 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_SHA256)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-SHA256_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult);
+
+       // Now verify the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now verify the MAC in a multiple part operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Check if bad key is refused
+       osslMac[10] ^= 0x11;
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(!mac->verifyFinal(osslMac));
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testHMACSHA384()
+{
+       char testData[4096] = "7D4C4274CFAFABE3605DE7E35B43F10251A441A6F4B03EE142B9EAE3DEC2E30E1A47FBE779D716427B108CCB2A2C2D7561B879B1C021E00E0498D91859BA3E7851EF3FC25A1BC6EADA8524EAEEDCC0E752AD90DFD0EA2F04B71B8ABF56DA85E4D070C91EC4B7723A02C3B52DAE31EEAF8E397CC3E92FA31E5F3292D8C9F45D459D8D1105E539D3979ADC01EB4E0C90BC33351295628BD0C2E1B4B13764EDD66BE9AD67AA7B4A7780264B0A3DBE099B190D25649B692401E0B758AB2A281B2E1AC9B4F7EE051C1B98BE92463F314A86A7FD40A4683A82457699F514563C70F1231C0B667C7B8CAD5910334CF894A9810D7C7C6DFC1E904D8512813A84911580C2AC56BB005A4FFB512A1290501AE795C832C0BF7DEBCD9B1D84CC0BB5B5F19D02FDBAB01F7B7CA47C99F3CB7D4F0D35622C267EBDADB2D089D0DA73FEA15A25C873C27EF72A84F99EC4E6980695BA6468B34B5AEC0746219468FEE88277739123FB51CEBF264140FFF27B94D6F751F26F0BC27387A2EFD038EEE43013AFC8FE94BE8E272B28ABFE2160BA81416113CBC2A1ADD96DD23F7107F4771CF2016501A8918A9A71C476CEDC10BB355BC144C818FD620301793CB16372A80881C5DFE387619ED651626CF44C8EDA8DA5BA8A6895148EE36037D4ADDBC13C5681935EDC5BD9B35F8E91B84C1F593B3E89614879CAE4DF4413E13655079F3CE21449CCA19E0963C925A75BC294F343016518D2F8FCB13ED38D574232602AD2416E94ED7735680439CE042145552F352156FCA722B31BFAA289C3711F170A845143ADFEF49CA53278358A7FECBD605AE9899192990D728CA37218B65DD9978EC4345100E174F3D04A0C8A5611263DABF7DA0BC6CE50BCD338830688B697FEB71909D1A2E09B62C5C4A8C1069C50C8DD6A432ED2B429F6BBFC304D0F0A35167BBDDCBC7F78959058393BC812820AF4917C56EA9233A1567608534F93857EA783B537CE294B4778E4B5D30D5836AE1F0D25B663A62512D2488E959D7FF000F8A70F31CC4CABB51D6F57A842AEABD707122935690F78F1F8BD7EC8544F1E70B9D6D53C50632F4DF5F0BC75630B427B28BAF2249C72F5864A3CE17627BA4F16F8FF13FA19DDF83736B171C024C95EFBC5D90615C495C2B02685C24C6E64E19C804B1DC138B5BC52A6969C4332F6113ED8C38F03A0107513C611A6FF013D2FC0B00859A6A5DFB8626002EA0126D477B5F9C7B5BEAB61A13AA8841A4C11E9DFB6A7164BBC2D40E940D9D10C56D58FBC76B92EA68425C2FF48BAE0CA2AF6F1CFBFFBBD855688C3960538E2D87088472CD73AB6D0FB86D9411310F5311EFCA3B89949A87D408B86B96C29C89A0180AF8957944E2A385A221081870CECC995FFDDD6994B0856ED0DC6303F7FDE5072F0B3D68BB132B0C5D3113939D614677720186052F4F90DD60A1CFD";
+       char testResult[512] = "AC387A4BB1E4E078C43C69087C206F49F56EC63CE244A429DA56B8EC3CAFBC987090DA7A8F6470874CA6049D20AC5154";
+
+       // Get a HMAC-SHA384 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_SHA384)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-SHA384_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult), shsmMac;
+
+       // Now recreate the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now recreate the MAC in a multiple part operation
+       shsmMac.wipe();
+
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->signUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac == shsmMac);
+
+       // Now recreate a different MAC
+       b[100] ^= 0x42;
+       CPPUNIT_ASSERT(mac->signInit(&key));
+       CPPUNIT_ASSERT(mac->signUpdate(b));
+       CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+
+       CPPUNIT_ASSERT(osslMac != shsmMac);
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testHMACSHA512()
+{
+       char testData[4096] = "A7A3B0B40CBAAB9B58F6946D9D15870B56E6832DECB708949EBF98DC4EC9C0AF477216C542A98A3646B6ABB72D89E6B3F18201CC75E93B37C2E8EADAD6827FBBFFD220642A92CABB587B27590ED204F8B2C926777C3DC9E5273CBB38582C103905C074002DAA2D8D16DD907BEFB4C51B49C464FF22B93269274291D1254889E3F677FBA6929AF472AECC02DECF822EABB2F05311E0BA8600B58075D4E49837F81C9565E37EAC96B9C2F3C08E3D818DD507D0CC8064C8CC7553D5A17204F4B92B74E5A441CF9142ED059DB1ADA76C799B10178FB3E76E4E3CAC6B1AD8648D522DCA6C93200E706D947E15422E1CC47742CCBF8E2C1E50492AFFA49BE22D5E34B0ACA62744626E2EF7014EAB17D8E538324D9A764501428A53593D23E3785831C1262F220883E2DEEFC66584A3AEC1F35998F842C5298A5E28653CF40F21C6E2383086C266E2902272198D45B38308904F5D2F614A6857E027D133C5455E75B16B9DB124755ADF06B16F04872D74D1A90F36709D8263B1190D625849F017930763AC1EA548DEC56BFD46D09F32D6ABAE96A778B39FBF22B1D6B3CA43F8E7ED32DB2254018FB1999ED0C4C3CDE710899CB20AB5E1CA706DA3E4E8E65253782379B49B7DEFE4E26DD498A935057E91B8FFB8B110336A554A6C61C26C2DDEEE8631926F8A706171B309B99E3B24030C17609340EBB82C4129B172B64CE6249FED00F05DCD624969BC1E4A29ED028C9821A812CDC310A974B959B29E30888887D9A8688E92F85E2A1683C5E993BCC584979F0B3F7DBE34295E2D852B6444EC4152A0C40F3113B402027E323231FC2EDD8078D6661F598588F68FB83DE9C2CA1491107E1F7B676BE16AA6C62B2FF86056905CFCE1FA57065B20A87B15BF1EADAC5FD94F5368451CE8CC2D363BC184A6E87D3D088CBCDE259845E4046D314660B1C1D4AFC7CCC37C7B1B8BBC7A54B63FE61FCD082966425AC3795F08BE7AFD6F9C66F2C3C50DD1EB6B8F8FC3C1A6A298A442EB6FC14AA906A7DA7854B53205E0A8F91C8D6CC3C41F4795FA70E14BA876548022733E61972F0351BC4187FFDE18E776BD68C5E947D2F0B19206D34770BA8ED63874639BBCEAA8D59771A02AEE654D20C69ACD8D16C42BAED6BD1AC51134F49C2A1D685B045527D4A86A7656439A2587F48F5AC43C5094DC680ECE19EBDD53B39F3B84F36D363D8CE464A20DE7ED50C6E32D5C7A9C3868D9823DF0E0A5FD824D239F67C41BC5AD3615AB51EA8B1A2C50B6D4C8F196F1278D9747B8C0B941509850052E63467950EBCE7B56D5E5C481D39E3958C51AE1267C075D8E62EC7F15400A5B4B91B15789015FBCCCC8186DC888CC0BC70326F1800FF56B01BC39DD1C2421BE6E142627B24822790DA36AD9CEA0661FAA03074FAA6F9EBC243DDCB249334B13D31DC19C0F03C6923CBFFEC6FAA29255";
+       char testResult[512] = "93E3A4336693965FEEC902F3BDDB064DD63D83EA1E46AA13DA209F8F000C15F366D3F9BE4F8AF189EA96D191D0BDE4CF0FC6C462C214B55ABF78F33BD6DF3DD0";
+
+       // Get a HMAC-SHA512 instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::HMAC_SHA512)) != NULL);
+
+       // Key
+       char pk[] = "a_key_for_HMAC-SHA512_test";
+       ByteString k((unsigned char *)pk, sizeof(pk));
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+
+       ByteString b(testData);
+       ByteString osslMac(testResult);
+
+       // Now verify the MAC using our implementation in a single operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       // Now verify the MAC in a multiple part operation
+       CPPUNIT_ASSERT(mac->verifyInit(&key));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, 567)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567, 989)));
+       CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(567 + 989)));
+       CPPUNIT_ASSERT(mac->verifyFinal(osslMac));
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testCMACDES2()
+{
+       // Test vectors from NIST SP 800-38B
+       char pk[33] = "4cf15134a2850dd58a3d10ba80570d38";
+       char testData[4][2][256] = {
+               {
+                       "",
+                       "bd2ebf9a3ba00361"
+               },
+               {
+                       "6bc1bee22e409f96",
+                       "4ff2ab813c53ce83"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a57",
+                       "62dd1b471902bd4e"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
+                       "31b1e431dabc4eb8"
+               }
+       };
+
+       // Get a CMAC-DES instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::CMAC_DES)) != NULL);
+
+       // Key
+       ByteString k(pk);
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+       key.setBitLen(112);
+
+       for (int i = 0; i < 4; i++)
+       {
+               ByteString b(testData[i][0]);
+               ByteString nistMac(testData[i][1]);
+               ByteString shsmMac;
+               size_t size, part1, part2;
+
+               // Now recreate the MAC using our implementation in a single operation
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a single operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+
+               // Now sign the MAC in a multiple part operation
+               shsmMac.wipe();
+               size = b.size();
+               part1 = size / 2;
+               part2 = size - part1;
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a multiple part operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+       }
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testCMACDES3()
+{
+       // Test vectors from NIST SP 800-38B
+       char pk[49] = "8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5";
+       char testData[4][2][256] = {
+               {
+                       "",
+                       "b7a688e122ffaf95"
+               },
+               {
+                       "6bc1bee22e409f96",
+                       "8e8f293136283797"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a57",
+                       "743ddbe0ce2dc2ed"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
+                       "33e6b1092400eae5"
+               }
+       };
+
+       // Get a CMAC-DES instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::CMAC_DES)) != NULL);
+
+       // Key
+       ByteString k(pk);
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+       key.setBitLen(168);
+
+       for (int i = 0; i < 4; i++)
+       {
+               ByteString b(testData[i][0]);
+               ByteString nistMac(testData[i][1]);
+               ByteString shsmMac;
+               size_t size, part1, part2;
+
+               // Now recreate the MAC using our implementation in a single operation
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a single operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+
+               // Now sign the MAC in a multiple part operation
+               shsmMac.wipe();
+               size = b.size();
+               part1 = size / 2;
+               part2 = size - part1;
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a multiple part operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+       }
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testCMACAES128()
+{
+       // Test vectors from NIST SP 800-38B
+       char pk[33] = "2b7e151628aed2a6abf7158809cf4f3c";
+       char testData[4][2][256] = {
+               {
+                       "",
+                       "bb1d6929e95937287fa37d129b756746"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172a",
+                       "070a16b46b4d4144f79bdd9dd04a287c"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411",
+                       "dfa66747de9ae63030ca32611497c827"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                       "51f0bebf7e3b9d92fc49741779363cfe"
+               }
+       };
+
+       // Get a CMAC-AES instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::CMAC_AES)) != NULL);
+
+       // Key
+       ByteString k(pk);
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+       key.setBitLen(128);
+
+       for (int i = 0; i < 4; i++)
+       {
+               ByteString b(testData[i][0]);
+               ByteString nistMac(testData[i][1]);
+               ByteString shsmMac;
+               size_t size, part1, part2;
+
+               // Now recreate the MAC using our implementation in a single operation
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a single operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+
+               // Now sign the MAC in a multiple part operation
+               shsmMac.wipe();
+               size = b.size();
+               part1 = size / 2;
+               part2 = size - part1;
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a multiple part operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+       }
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testCMACAES192()
+{
+       // Test vectors from NIST SP 800-38B
+       char pk[49] = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
+       char testData[4][2][256] = {
+               {
+                       "",
+                       "d17ddf46adaacde531cac483de7a9367"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172a",
+                       "9e99a7bf31e710900662f65e617c5184"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411",
+                       "8a1de5be2eb31aad089a82e6ee908b0e"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                       "a1d5df0eed790f794d77589659f39a11"
+               }
+       };
+
+       // Get a CMAC-AES instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::CMAC_AES)) != NULL);
+
+       // Key
+       ByteString k(pk);
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+       key.setBitLen(192);
+
+       for (int i = 0; i < 4; i++)
+       {
+               ByteString b(testData[i][0]);
+               ByteString nistMac(testData[i][1]);
+               ByteString shsmMac;
+               size_t size, part1, part2;
+
+               // Now recreate the MAC using our implementation in a single operation
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a single operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+
+               // Now sign the MAC in a multiple part operation
+               shsmMac.wipe();
+               size = b.size();
+               part1 = size / 2;
+               part2 = size - part1;
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a multiple part operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+       }
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
+
+void MacTests::testCMACAES256()
+{
+       // Test vectors from NIST SP 800-38B
+       char pk[65] = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
+       char testData[4][2][256] = {
+               {
+                       "",
+                       "028962f61b7bf89efc6b551f4667d983"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172a",
+                       "28a7023f452e8f82bd4bf28d8c37c35c"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411",
+                       "aaf3d8f1de5640c232f5b169b9c911e6"
+               },
+               {
+                       "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                       "e1992190549f6ed5696a2c056c315410"
+               }
+       };
+
+       // Get a CMAC-AES instance
+       CPPUNIT_ASSERT((mac = CryptoFactory::i()->getMacAlgorithm(MacAlgo::CMAC_AES)) != NULL);
+
+       // Key
+       ByteString k(pk);
+       SymmetricKey key;
+       CPPUNIT_ASSERT(key.setKeyBits(k));
+       key.setBitLen(256);
+
+       for (int i = 0; i < 4; i++)
+       {
+               ByteString b(testData[i][0]);
+               ByteString nistMac(testData[i][1]);
+               ByteString shsmMac;
+               size_t size, part1, part2;
+
+               // Now recreate the MAC using our implementation in a single operation
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a single operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+
+               // Now sign the MAC in a multiple part operation
+               shsmMac.wipe();
+               size = b.size();
+               part1 = size / 2;
+               part2 = size - part1;
+               CPPUNIT_ASSERT(mac->signInit(&key));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->signUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->signFinal(shsmMac));
+               CPPUNIT_ASSERT(nistMac == shsmMac);
+
+               // Now verify the MAC in a multiple part operation
+               CPPUNIT_ASSERT(mac->verifyInit(&key));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(0, part1)));
+               CPPUNIT_ASSERT(mac->verifyUpdate(b.substr(part2)));
+               CPPUNIT_ASSERT(mac->verifyFinal(nistMac));
+       }
+
+       CryptoFactory::i()->recycleMacAlgorithm(mac);
+
+       mac = NULL;
+       rng = NULL;
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/MacTests.h b/SoftHSMv2/src/lib/crypto/test/MacTests.h
new file mode 100644 (file)
index 0000000..9e6fa99
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ MacTests.h
+
+ Contains test cases to test the MAC implementations
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_MACTESTS_H
+#define _SOFTHSM_V2_MACTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "MacAlgorithm.h"
+#include "RNG.h"
+
+class MacTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(MacTests);
+#ifndef WITH_FIPS
+       CPPUNIT_TEST(testHMACMD5);
+#endif
+       CPPUNIT_TEST(testHMACSHA1);
+       CPPUNIT_TEST(testHMACSHA224);
+       CPPUNIT_TEST(testHMACSHA256);
+       CPPUNIT_TEST(testHMACSHA384);
+       CPPUNIT_TEST(testHMACSHA512);
+       CPPUNIT_TEST(testCMACDES2);
+       CPPUNIT_TEST(testCMACDES3);
+       CPPUNIT_TEST(testCMACAES128);
+       CPPUNIT_TEST(testCMACAES192);
+       CPPUNIT_TEST(testCMACAES256);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+#ifndef WITH_FIPS
+       void testHMACMD5();
+#endif
+       void testHMACSHA1();
+       void testHMACSHA224();
+       void testHMACSHA256();
+       void testHMACSHA384();
+       void testHMACSHA512();
+       void testCMACDES2();
+       void testCMACDES3();
+       void testCMACAES128();
+       void testCMACAES192();
+       void testCMACAES256();
+
+       void setUp();
+       void tearDown();
+
+private:
+       MacAlgorithm* mac;
+
+       RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_MACTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/Makefile.am b/SoftHSMv2/src/lib/crypto/test/Makefile.am
new file mode 100644 (file)
index 0000000..bf63ae6
--- /dev/null
@@ -0,0 +1,39 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../.. \
+                               -I$(srcdir)/../../common \
+                               -I$(srcdir)/../../data_mgr \
+                               -I$(srcdir)/../../object_store \
+                               -I$(srcdir)/../../pkcs11 \
+                               -I$(srcdir)/../../session_mgr \
+                               -I$(srcdir)/../../slot_mgr \
+                               @CPPUNIT_CFLAGS@ \
+                               @CRYPTO_INCLUDES@
+
+check_PROGRAMS =               cryptotest
+
+cryptotest_SOURCES =           cryptotest.cpp \
+                               AESTests.cpp \
+                               DESTests.cpp \
+                               DHTests.cpp \
+                               DSATests.cpp \
+                               ECDHTests.cpp \
+                               ECDSATests.cpp \
+                               GOSTTests.cpp \
+                               HashTests.cpp \
+                               MacTests.cpp \
+                               RNGTests.cpp \
+                               RSATests.cpp \
+                               chisq.c \
+                               ent.c \
+                               iso8859.c \
+                               randtest.c
+
+cryptotest_LDADD =             ../../libsofthsm_convarch.la
+
+cryptotest_LDFLAGS =           @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install
+
+TESTS =                        cryptotest
+
+EXTRA_DIST =                   $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/crypto/test/RNGTests.cpp b/SoftHSMv2/src/lib/crypto/test/RNGTests.cpp
new file mode 100644 (file)
index 0000000..da793b5
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RNGTests.cpp
+
+ Contains test cases to test the RNG class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "RNGTests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "ent.h"
+#include <stdio.h>
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RNGTests);
+
+void RNGTests::setUp()
+{
+       rng = NULL;
+
+       rng = CryptoFactory::i()->getRNG();
+
+       // Check the RNG
+       CPPUNIT_ASSERT(rng != NULL);
+}
+
+void RNGTests::tearDown()
+{
+       fflush(stdout);
+}
+
+void RNGTests::testSimpleComparison()
+{
+       ByteString a,b;
+
+       CPPUNIT_ASSERT(rng->generateRandom(a, 256));
+       CPPUNIT_ASSERT(rng->generateRandom(b, 256));
+       CPPUNIT_ASSERT(a.size() == 256);
+       CPPUNIT_ASSERT(b.size() == 256);
+       CPPUNIT_ASSERT(a != b);
+}
+
+void RNGTests::testEnt()
+{
+       ByteString a;
+       double entropy, chiProbability, arithMean, montePi, serialCorrelation;
+
+       // Generate 10MB of random data
+       CPPUNIT_ASSERT(rng->generateRandom(a, 10*1024*1024));
+
+       // Perform entropy tests
+       doEnt(a.byte_str(), a.size(), &entropy, &chiProbability, &arithMean, &montePi, &serialCorrelation);
+
+       // Check entropy
+       CPPUNIT_ASSERT(entropy >= 7.999);
+       CPPUNIT_ASSERT((arithMean >= 127.4) && (arithMean <= 127.6));
+       CPPUNIT_ASSERT(serialCorrelation <= 0.001);
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/test/RNGTests.h b/SoftHSMv2/src/lib/crypto/test/RNGTests.h
new file mode 100644 (file)
index 0000000..1391d81
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RNGTests.h
+
+ Contains test cases to test the RNG class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RNGTESTS_H
+#define _SOFTHSM_V2_RNGTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "RNG.h"
+
+class RNGTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(RNGTests);
+       CPPUNIT_TEST(testSimpleComparison);
+       CPPUNIT_TEST(testEnt);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testSimpleComparison();
+       void testEnt();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // RNG instance
+       RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_RNGTESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/RSATests.cpp b/SoftHSMv2/src/lib/crypto/test/RSATests.cpp
new file mode 100644 (file)
index 0000000..6af1e19
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSATests.cpp
+
+ Contains test cases to test the RNG class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <vector>
+#include <cppunit/extensions/HelperMacros.h>
+#include "RSATests.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "AsymmetricKeyPair.h"
+#include "AsymmetricAlgorithm.h"
+#include "RSAParameters.h"
+#include "RSAPublicKey.h"
+#include "RSAPrivateKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RSATests);
+
+void RSATests::setUp()
+{
+       rsa = NULL;
+
+       rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA);
+
+       // Check the RSA object
+       CPPUNIT_ASSERT(rsa != NULL);
+}
+
+void RSATests::tearDown()
+{
+       if (rsa != NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa);
+       }
+
+       fflush(stdout);
+}
+
+void RSATests::testKeyGeneration()
+{
+       AsymmetricKeyPair* kp;
+       RSAParameters p;
+
+       // Public exponents to test
+       std::vector<ByteString> exponents;
+       exponents.push_back("010001");
+       exponents.push_back("03");
+       exponents.push_back("0B");
+       exponents.push_back("11");
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+       keySizes.push_back(1024);
+#ifndef WITH_FIPS
+       keySizes.push_back(1025);
+#endif
+       keySizes.push_back(1280);
+       keySizes.push_back(2048);
+       //keySizes.push_back(4096);
+
+       for (std::vector<ByteString>::iterator e = exponents.begin(); e != exponents.end(); e++)
+       {
+               for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+               {
+                       p.setE(*e);
+                       p.setBitLength(*k);
+
+                       // Generate key-pair
+                       CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p));
+
+                       RSAPublicKey* pub = (RSAPublicKey*) kp->getPublicKey();
+                       RSAPrivateKey* priv = (RSAPrivateKey*) kp->getPrivateKey();
+
+                       CPPUNIT_ASSERT(pub->getBitLength() == *k);
+                       CPPUNIT_ASSERT(priv->getBitLength() == *k);
+                       CPPUNIT_ASSERT(pub->getE() == *e);
+                       CPPUNIT_ASSERT(priv->getE() == *e);
+
+                       rsa->recycleKeyPair(kp);
+               }
+       }
+}
+
+void RSATests::testSerialisation()
+{
+       // Generate a 1024-bit key-pair for testing
+       AsymmetricKeyPair* kp;
+       RSAParameters p;
+
+       p.setE("010001");
+       p.setBitLength(1024);
+
+       CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       // Serialise the parameters
+       ByteString serialisedParams = p.serialise();
+
+       // Deserialise the parameters
+       AsymmetricParameters* dP;
+
+       CPPUNIT_ASSERT(rsa->reconstructParameters(&dP, serialisedParams));
+       CPPUNIT_ASSERT(dP->areOfType(RSAParameters::type));
+
+       RSAParameters* ddP = (RSAParameters*) dP;
+
+       CPPUNIT_ASSERT(p.getE() == ddP->getE());
+       CPPUNIT_ASSERT(p.getBitLength() == ddP->getBitLength());
+       rsa->recycleParameters(dP);
+
+       // Serialise the key-pair
+       ByteString serialisedKP = kp->serialise();
+
+       CPPUNIT_ASSERT(serialisedKP.size() != 0);
+
+       // Deserialise the key-pair
+       AsymmetricKeyPair* dKP;
+
+       CPPUNIT_ASSERT(rsa->reconstructKeyPair(&dKP, serialisedKP));
+       CPPUNIT_ASSERT(serialisedKP.size() == 0);
+       CPPUNIT_ASSERT(dKP != NULL);
+
+       RSAPublicKey* pub = (RSAPublicKey*) kp->getPublicKey();
+       RSAPrivateKey* priv = (RSAPrivateKey*) kp->getPrivateKey();
+
+       RSAPublicKey* dPub = (RSAPublicKey*) dKP->getPublicKey();
+       RSAPrivateKey* dPriv = (RSAPrivateKey*) dKP->getPrivateKey();
+
+       CPPUNIT_ASSERT(pub->getN() == dPub->getN());
+       CPPUNIT_ASSERT(pub->getE() == dPub->getE());
+
+       CPPUNIT_ASSERT(priv->getP() == dPriv->getP());
+       CPPUNIT_ASSERT(priv->getQ() == dPriv->getQ());
+       CPPUNIT_ASSERT(priv->getPQ() == dPriv->getPQ());
+       CPPUNIT_ASSERT(priv->getDP1() == dPriv->getDP1());
+       CPPUNIT_ASSERT(priv->getDQ1() == dPriv->getDQ1());
+       CPPUNIT_ASSERT(priv->getD() == dPriv->getD());
+       CPPUNIT_ASSERT(priv->getN() == dPriv->getN());
+       CPPUNIT_ASSERT(priv->getE() == dPriv->getE());
+
+       // Serialise and deserialise the public key
+       ByteString serialisedPub = pub->serialise();
+
+       RSAPublicKey* desPub;
+
+       CPPUNIT_ASSERT(rsa->reconstructPublicKey((PublicKey**) &desPub, serialisedPub));
+       CPPUNIT_ASSERT(serialisedPub.size() == 0);
+       CPPUNIT_ASSERT(desPub != NULL);
+
+       CPPUNIT_ASSERT(pub->getN() == desPub->getN());
+       CPPUNIT_ASSERT(pub->getE() == desPub->getE());
+
+       // Serialise and deserialise the private key
+       ByteString serialisedPriv = priv->serialise();
+
+       RSAPrivateKey* desPriv;
+
+       CPPUNIT_ASSERT(rsa->reconstructPrivateKey((PrivateKey**) &desPriv, serialisedPriv));
+       CPPUNIT_ASSERT(serialisedPriv.size() == 0);
+       CPPUNIT_ASSERT(desPriv != NULL);
+
+       CPPUNIT_ASSERT(priv->getP() == desPriv->getP());
+       CPPUNIT_ASSERT(priv->getQ() == desPriv->getQ());
+       CPPUNIT_ASSERT(priv->getPQ() == desPriv->getPQ());
+       CPPUNIT_ASSERT(priv->getDP1() == desPriv->getDP1());
+       CPPUNIT_ASSERT(priv->getDQ1() == desPriv->getDQ1());
+       CPPUNIT_ASSERT(priv->getD() == desPriv->getD());
+       CPPUNIT_ASSERT(priv->getN() == desPriv->getN());
+       CPPUNIT_ASSERT(priv->getE() == desPriv->getE());
+
+       rsa->recycleKeyPair(kp);
+       rsa->recycleKeyPair(dKP);
+       rsa->recyclePublicKey(desPub);
+       rsa->recyclePrivateKey(desPriv);
+}
+
+void RSATests::testPKCS8()
+{
+       // Generate a 1024-bit key-pair for testing
+       AsymmetricKeyPair* kp;
+       RSAParameters p;
+
+       p.setE("010001");
+       p.setBitLength(1024);
+
+       CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p));
+       CPPUNIT_ASSERT(kp != NULL);
+
+       RSAPrivateKey* priv = (RSAPrivateKey*) kp->getPrivateKey();
+       CPPUNIT_ASSERT(priv != NULL);
+
+       // Encode and decode the private key
+       ByteString pkcs8 = priv->PKCS8Encode();
+       CPPUNIT_ASSERT(pkcs8.size() != 0);
+
+       RSAPrivateKey* dPriv = (RSAPrivateKey*) rsa->newPrivateKey();
+       CPPUNIT_ASSERT(dPriv != NULL);
+
+       CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
+
+       CPPUNIT_ASSERT(priv->getP() == dPriv->getP());
+       CPPUNIT_ASSERT(priv->getQ() == dPriv->getQ());
+       CPPUNIT_ASSERT(priv->getPQ() == dPriv->getPQ());
+       CPPUNIT_ASSERT(priv->getDP1() == dPriv->getDP1());
+       CPPUNIT_ASSERT(priv->getDQ1() == dPriv->getDQ1());
+       CPPUNIT_ASSERT(priv->getD() == dPriv->getD());
+       CPPUNIT_ASSERT(priv->getN() == dPriv->getN());
+       CPPUNIT_ASSERT(priv->getE() == dPriv->getE());
+
+       rsa->recycleKeyPair(kp);
+       rsa->recyclePrivateKey(dPriv);
+}
+
+void RSATests::testSigningVerifying()
+{
+       AsymmetricKeyPair* kp;
+       RSAParameters p;
+
+       // Public exponents to test
+       std::vector<ByteString> exponents;
+       exponents.push_back("010001");
+       exponents.push_back("03");
+       exponents.push_back("0B");
+       exponents.push_back("11");
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+       keySizes.push_back(1024);
+       keySizes.push_back(1280);
+       keySizes.push_back(2048);
+       //keySizes.push_back(4096);
+
+       // Mechanisms to test
+       std::vector<AsymMech::Type> mechanisms;
+#ifndef WITH_FIPS
+       mechanisms.push_back(AsymMech::RSA_MD5_PKCS);
+#endif
+       mechanisms.push_back(AsymMech::RSA_SHA1_PKCS);
+       mechanisms.push_back(AsymMech::RSA_SHA224_PKCS);
+       mechanisms.push_back(AsymMech::RSA_SHA256_PKCS);
+       mechanisms.push_back(AsymMech::RSA_SHA384_PKCS);
+       mechanisms.push_back(AsymMech::RSA_SHA512_PKCS);
+       mechanisms.push_back(AsymMech::RSA_SHA1_PKCS_PSS);
+       mechanisms.push_back(AsymMech::RSA_SHA224_PKCS_PSS);
+       mechanisms.push_back(AsymMech::RSA_SHA256_PKCS_PSS);
+       mechanisms.push_back(AsymMech::RSA_SHA384_PKCS_PSS);
+       mechanisms.push_back(AsymMech::RSA_SHA512_PKCS_PSS);
+#ifndef WITH_FIPS
+       mechanisms.push_back(AsymMech::RSA_SSL);
+#endif
+
+       /* Max salt length for SHA512 and 1024-bit RSA is 62 bytes */
+       RSA_PKCS_PSS_PARAMS pssParams[] = {
+               { HashAlgo::SHA1,   AsymRSAMGF::MGF1_SHA1,   20 },
+               { HashAlgo::SHA224, AsymRSAMGF::MGF1_SHA224, 0  },
+               { HashAlgo::SHA256, AsymRSAMGF::MGF1_SHA256, 0  },
+               { HashAlgo::SHA384, AsymRSAMGF::MGF1_SHA384, 48 },
+               { HashAlgo::SHA512, AsymRSAMGF::MGF1_SHA512, 62 }
+       };
+
+       for (std::vector<ByteString>::iterator e = exponents.begin(); e != exponents.end(); e++)
+       {
+               for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+               {
+                       p.setE(*e);
+                       p.setBitLength(*k);
+
+                       // Generate key-pair
+                       CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p));
+
+                       // Generate some data to sign
+                       ByteString dataToSign;
+
+                       RNG* rng = CryptoFactory::i()->getRNG();
+
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567));
+
+                       // Test mechanisms that perform internal hashing
+                       for (std::vector<AsymMech::Type>::iterator m = mechanisms.begin(); m != mechanisms.end(); m++)
+                       {
+                               ByteString blockSignature, singlePartSignature;
+                               void* param = NULL;
+                               size_t paramLen = 0;
+                               bool isPSS = false;
+
+                               switch (*m)
+                               {
+                                       case AsymMech::RSA_SHA1_PKCS_PSS:
+                                               param = &pssParams[0];
+                                               paramLen = sizeof(pssParams[0]);
+                                               isPSS = true;
+                                               break;
+                                       case AsymMech::RSA_SHA224_PKCS_PSS:
+                                               param = &pssParams[1];
+                                               paramLen = sizeof(pssParams[1]);
+                                               isPSS = true;
+                                               break;
+                                       case AsymMech::RSA_SHA256_PKCS_PSS:
+                                               param = &pssParams[2];
+                                               paramLen = sizeof(pssParams[2]);
+                                               isPSS = true;
+                                               break;
+                                       case AsymMech::RSA_SHA384_PKCS_PSS:
+                                               param = &pssParams[3];
+                                               paramLen = sizeof(pssParams[3]);
+                                               isPSS = true;
+                                               break;
+                                       case AsymMech::RSA_SHA512_PKCS_PSS:
+                                               param = &pssParams[4];
+                                               paramLen = sizeof(pssParams[4]);
+                                               isPSS = true;
+                                               break;
+                                       default:
+                                               break;
+                               }
+
+                               // Sign the data in blocks
+                               CPPUNIT_ASSERT(rsa->signInit(kp->getPrivateKey(), *m, param, paramLen));
+                               CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(0, 134)));
+                               CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(134, 289)));
+                               CPPUNIT_ASSERT(rsa->signUpdate(dataToSign.substr(134 + 289)));
+                               CPPUNIT_ASSERT(rsa->signFinal(blockSignature));
+
+                               // Sign the data in one pass
+                               CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, singlePartSignature, *m, param, paramLen));
+
+                               // If it is not a PSS signature, check if the two signatures match
+                               if (!isPSS)
+                               {
+                                       // Check if the two signatures match
+                                       CPPUNIT_ASSERT(blockSignature == singlePartSignature);
+                               }
+
+                               // Now perform multi-pass verification
+                               CPPUNIT_ASSERT(rsa->verifyInit(kp->getPublicKey(), *m, param, paramLen));
+                               CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(0, 125)));
+                               CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(125, 247)));
+                               CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign.substr(125 + 247)));
+                               CPPUNIT_ASSERT(rsa->verifyFinal(blockSignature));
+
+                               // And single-pass verification
+                               CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, singlePartSignature, *m, param, paramLen));
+                       }
+
+                       // Test mechanisms that do not perform internal hashing
+
+                       // Test PKCS #1 signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 35));
+
+                       // Sign the data
+                       ByteString signature;
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS));
+
+                       // Verify the signature
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS));
+
+                       // Test raw RSA signing
+                       size_t byteSize = *k >> 3;
+
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, byteSize));
+
+                       // Strip the topmost bit
+                       dataToSign[0] &= 0x7F;
+
+                       // Sign the data
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA));
+
+                       // Verify the signature
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA));
+
+#ifdef WITH_RAW_PSS
+                       // Test raw (SHA1) PKCS PSS signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 20));
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[0], sizeof(pssParams[0])));
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[0], sizeof(pssParams[0])));
+
+                       // Test raw (SHA224) PKCS PSS signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 28));
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[1], sizeof(pssParams[1])));
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[1], sizeof(pssParams[1])));
+
+                       // Test raw (SHA256) PKCS PSS signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 32));
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[2], sizeof(pssParams[2])));
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[2], sizeof(pssParams[2])));
+
+                       // Test raw (SHA384) PKCS PSS signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 48));
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[3], sizeof(pssParams[3])));
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[3], sizeof(pssParams[3])));
+
+                       // Test raw (SHA512) PKCS PSS signing
+                       CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 64));
+                       CPPUNIT_ASSERT(rsa->sign(kp->getPrivateKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[4], sizeof(pssParams[4])));
+                       CPPUNIT_ASSERT(rsa->verify(kp->getPublicKey(), dataToSign, signature, AsymMech::RSA_PKCS_PSS, &pssParams[4], sizeof(pssParams[4])));
+#endif
+
+                       rsa->recycleKeyPair(kp);
+               }
+       }
+}
+
+void RSATests::testSignVerifyKnownVector()
+{
+       // These test vectors were taken from the Crypto++ set of test vectors
+       // Crypto++ can be downloaded from www.cryptopp.com
+
+#ifndef WITH_FIPS
+       RSAPublicKey* pubKey1 = (RSAPublicKey*) rsa->newPublicKey();
+       RSAPublicKey* pubKey2 = (RSAPublicKey*) rsa->newPublicKey();
+#endif
+       RSAPublicKey* pubKey3 = (RSAPublicKey*) rsa->newPublicKey();
+#ifndef WITH_FIPS
+       RSAPrivateKey* privKey1_1 = (RSAPrivateKey*) rsa->newPrivateKey();
+       RSAPrivateKey* privKey1_2 = (RSAPrivateKey*) rsa->newPrivateKey();
+       RSAPrivateKey* privKey2_1 = (RSAPrivateKey*) rsa->newPrivateKey();
+       RSAPrivateKey* privKey2_2 = (RSAPrivateKey*) rsa->newPrivateKey();
+#endif
+       RSAPrivateKey* privKey3 = (RSAPrivateKey*) rsa->newPrivateKey();
+
+#ifndef WITH_FIPS
+       // Reconstruct public and private key #1
+       ByteString n1   = "0A66791DC6988168DE7AB77419BB7FB0C001C62710270075142942E19A8D8C51D053B3E3782A1DE5DC5AF4EBE99468170114A1DFE67CDC9A9AF55D655620BBAB";
+       ByteString e1   = "010001";
+       ByteString d1   = "0123C5B61BA36EDB1D3679904199A89EA80C09B9122E1400C09ADCF7784676D01D23356A7D44D6BD8BD50E94BFC723FA87D8862B75177691C11D757692DF8881";
+       ByteString p1   = "33D48445C859E52340DE704BCDDA065FBB4058D740BD1D67D29E9C146C11CF61";
+       ByteString q1   = "335E8408866B0FD38DC7002D3F972C67389A65D5D8306566D5C4F2A5AA52628B";
+       ByteString dp11 = "045EC90071525325D3D46DB79695E9AFACC4523964360E02B119BAA366316241";
+       ByteString dq11 = "15EB327360C7B60D12E5E2D16BDCD97981D17FBA6B70DB13B20B436E24EADA59";
+       ByteString pq1  = "2CA6366D72781DFA24D34A9A24CBC2AE927A9958AF426563FF63FB11658A461D";
+
+       pubKey1->setN(n1);
+       pubKey1->setE(e1);
+       privKey1_1->setN(n1);
+       privKey1_1->setE(e1);
+       privKey1_1->setD(d1);
+       privKey1_1->setP(p1);
+       privKey1_1->setQ(q1);
+       privKey1_1->setDP1(dp11);
+       privKey1_1->setDQ1(dq11);
+       privKey1_1->setPQ(pq1);
+
+       // The same key but without CRT factors
+       privKey1_2->setN(n1);
+       privKey1_2->setE(e1);
+       privKey1_2->setD(d1);
+
+       // Reconstruct public and private key #2
+       ByteString n2   = "A885B6F851A8079AB8A281DB0297148511EE0D8C07C0D4AE6D6FED461488E0D41E3FF8F281B06A3240B5007A5C2AB4FB6BE8AF88F119DB998368DDDC9710ABED";
+       ByteString e2   = "010001";
+       ByteString d2   = "2B259D2CA3DF851EE891F6F4678BDDFD9A131C95D3305C63D2723B4A5B9C960F5EC8BB7DCDDBEBD8B6A38767D64AD451E9383E0891E4EE7506100481F2B49323";
+       ByteString p2   = "D7103CD676E39824E2BE50B8E6533FE7CB7484348E283802AD2B8D00C80D19DF";
+       ByteString q2   = "C89996DC169CEB3F227958275968804D4BE9FC4012C3219662F1A438C9950BB3";
+       ByteString dp12 = "5D8EA4C8AF83A70634D5920C3DB66D908AC3AF57A597FD75BC9BBB856181C185";
+       ByteString dq12 = "C598E54DAEC8ABC1E907769A6C2BD01653ED0C9960E1EDB7E186FDA922883A99";
+       ByteString pq2  = "7C6F27B5B51B78AD80FB36E700990CF307866F2943124CBD93D97C137794C104";
+
+       pubKey2->setN(n2);
+       pubKey2->setE(e2);
+       privKey2_1->setN(n2);
+       privKey2_1->setE(e2);
+       privKey2_1->setD(d2);
+       privKey2_1->setP(p2);
+       privKey2_1->setQ(q2);
+       privKey2_1->setDP1(dp12);
+       privKey2_1->setDQ1(dq12);
+       privKey2_1->setPQ(pq2);
+
+       // The same key but without CRT factors
+       privKey2_2->setN(n2);
+       privKey2_2->setE(e2);
+       privKey2_2->setD(d2);
+#endif
+
+       ByteString n3   = "A8D68ACD413C5E195D5EF04E1B4FAAF242365CB450196755E92E1215BA59802AAFBADBF2564DD550956ABB54F8B1C917844E5F36195D1088C600E07CADA5C080EDE679F50B3DE32CF4026E514542495C54B1903768791AAE9E36F082CD38E941ADA89BAECADA61AB0DD37AD536BCB0A0946271594836E92AB5517301D45176B5";
+       ByteString e3   = "03";
+       ByteString d3   = "1C23C1CCE034BA598F8FD2B7AF37F1D30B090F7362AEE68E5187ADAE49B9955C729F24A863B7A38D6E3C748E2972F6D940B7BA89043A2D6C2100256A1CF0F56A8CD35FC6EE205244876642F6F9C3820A3D9D2C8921DF7D82AAADCAF2D7334D398931DDBBA553190B3A416099F3AA07FD5B26214645A828419E122CFB857AD73B";
+       ByteString p3   = "C107a2fe924b76e206cb9bc4af2ab7008547c00846bf6d0680b3eac3ebcbd0c7fd7a54c2b9899b08f80cde1d3691eaaa2816b1eb11822d6be7beaf4e30977c49";
+       ByteString q3   = "DFEA984CE4307EAFC0D140C2BB82861E5DBAC4F8567CBC981D70440DD639492079031486315E305EB83E591C4A2E96064966F7C894C3CA351925B5CE82D8EF0D";
+
+       pubKey3->setN(n3);
+       pubKey3->setE(e3);
+       privKey3->setN(n3);
+       privKey3->setE(e3);
+       privKey3->setD(d3);
+       privKey3->setP(p3);
+       privKey3->setQ(q3);
+
+#ifndef WITH_FIPS
+       // Test with key #1
+       const char* testValue1 = "Everyone gets Friday off.";
+
+       ByteString dataToSign1((const unsigned char*) testValue1, strlen(testValue1));
+
+       ByteString expectedSignature1 = "0610761F95FFD1B8F29DA34212947EC2AA0E358866A722F03CC3C41487ADC604A48FF54F5C6BEDB9FB7BD59F82D6E55D8F3174BA361B2214B2D74E8825E04E81";
+       ByteString signature1_1;
+       ByteString signature1_2;
+
+       CPPUNIT_ASSERT(rsa->signInit(privKey1_1, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->signUpdate(dataToSign1));
+       CPPUNIT_ASSERT(rsa->signFinal(signature1_1));
+
+#ifndef WITH_BOTAN
+       CPPUNIT_ASSERT(rsa->signInit(privKey1_2, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->signUpdate(dataToSign1));
+       CPPUNIT_ASSERT(rsa->signFinal(signature1_2));
+
+       CPPUNIT_ASSERT(signature1_1 == signature1_2);
+#endif
+       CPPUNIT_ASSERT(signature1_1 == expectedSignature1);
+
+       CPPUNIT_ASSERT(rsa->verifyInit(pubKey1, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign1));
+       CPPUNIT_ASSERT(rsa->verifyFinal(expectedSignature1));
+
+       // Test with key #2
+       const char* testValue2 = "test";
+
+       ByteString dataToSign2((const unsigned char*) testValue2, strlen(testValue2));
+
+       ByteString expectedSignature2 = "A7E00CE4391F914D82158D9B732759808E25A1C6383FE87A5199157650D4296CF612E9FF809E686A0AF328238306E79965F6D0138138829D9A1A22764306F6CE";
+       ByteString signature2_1;
+       ByteString signature2_2;
+
+       CPPUNIT_ASSERT(rsa->signInit(privKey2_1, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->signUpdate(dataToSign2));
+       CPPUNIT_ASSERT(rsa->signFinal(signature2_1));
+
+#ifndef WITH_BOTAN
+       CPPUNIT_ASSERT(rsa->signInit(privKey2_2, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->signUpdate(dataToSign2));
+       CPPUNIT_ASSERT(rsa->signFinal(signature2_2));
+
+       CPPUNIT_ASSERT(signature2_1 == signature2_2);
+#endif
+       CPPUNIT_ASSERT(signature2_1 == expectedSignature2);
+
+       CPPUNIT_ASSERT(rsa->verifyInit(pubKey2, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign2));
+       CPPUNIT_ASSERT(rsa->verifyFinal(expectedSignature2));
+#endif
+
+       // Test with key #3
+       ByteString dataToSign3 = "D73829497CDDBE41B705FAAC50E7899FDB5A38BF3A459E536357029E64F8796BA47F4FE96BA5A8B9A4396746E2164F55A25368DDD0B9A5188C7AC3DA2D1F742286C3BDEE697F9D546A25EFCFE53191D743FCC6B47833D993D08804DAECA78FB9076C3C017F53E33A90305AF06220974D46BF19ED3C9B84EDBAE98B45A8771258";
+       ByteString expectedSignature3 = "175015BDA50ABE0FA7D39A8353885CA01BE3A7E7FCC55045744111362EE1914473A48DC537D956294B9E20A1EF661D58537ACDC8DE908FA050630FCC272E6D001045E6FDEED2D10531C8603334C2E8DB39E73E6D9665EE1343F9E4198302D2201B44E8E8D06B3EF49CEE6197582163A8490089CA654C0012FCE1BA6511089750";
+       ByteString signature3;
+
+       CPPUNIT_ASSERT(rsa->signInit(privKey3, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->signUpdate(dataToSign3));
+       CPPUNIT_ASSERT(rsa->signFinal(signature3));
+
+       CPPUNIT_ASSERT(signature3 == expectedSignature3);
+
+       CPPUNIT_ASSERT(rsa->verifyInit(pubKey3, AsymMech::RSA_SHA1_PKCS));
+       CPPUNIT_ASSERT(rsa->verifyUpdate(dataToSign3));
+       CPPUNIT_ASSERT(rsa->verifyFinal(expectedSignature3));
+
+#ifndef WITH_FIPS
+       rsa->recyclePublicKey(pubKey1);
+       rsa->recyclePublicKey(pubKey2);
+#endif
+       rsa->recyclePublicKey(pubKey3);
+#ifndef WITH_FIPS
+       rsa->recyclePrivateKey(privKey1_1);
+       rsa->recyclePrivateKey(privKey1_2);
+       rsa->recyclePrivateKey(privKey2_1);
+       rsa->recyclePrivateKey(privKey2_2);
+#endif
+       rsa->recyclePrivateKey(privKey3);
+}
+
+void RSATests::testEncryptDecrypt()
+{
+       AsymmetricKeyPair* kp;
+       RSAParameters p;
+
+       // Public exponents to test
+       std::vector<ByteString> exponents;
+       exponents.push_back("010001");
+       exponents.push_back("03");
+       exponents.push_back("0B");
+       exponents.push_back("11");
+
+       // Key sizes to test
+       std::vector<size_t> keySizes;
+       keySizes.push_back(1024);
+       keySizes.push_back(1280);
+       keySizes.push_back(2048);
+       //keySizes.push_back(4096);
+
+       // Paddings to test
+       std::vector<AsymMech::Type> paddings;
+       paddings.push_back(AsymMech::RSA_PKCS);
+       paddings.push_back(AsymMech::RSA_PKCS_OAEP);
+       paddings.push_back(AsymMech::RSA);
+
+       for (std::vector<ByteString>::iterator e = exponents.begin(); e != exponents.end(); e++)
+       {
+               for (std::vector<size_t>::iterator k = keySizes.begin(); k != keySizes.end(); k++)
+               {
+                       p.setE(*e);
+                       p.setBitLength(*k);
+
+                       // Generate key-pair
+                       CPPUNIT_ASSERT(rsa->generateKeyPair(&kp, &p));
+
+                       RNG* rng = CryptoFactory::i()->getRNG();
+
+                       for (std::vector<AsymMech::Type>::iterator pad = paddings.begin(); pad != paddings.end(); pad++)
+                       {
+                               // Generate some test data to encrypt based on the selected padding
+                               ByteString testData;
+
+                               if (*pad == AsymMech::RSA_PKCS)
+                               {
+                                       CPPUNIT_ASSERT(rng->generateRandom(testData, (*k >> 3) - 12));
+                               }
+                               else if (*pad == AsymMech::RSA_PKCS_OAEP)
+                               {
+                                       CPPUNIT_ASSERT(rng->generateRandom(testData, (*k >> 3) - 42));
+                               }
+                               else if (*pad == AsymMech::RSA)
+                               {
+                                       CPPUNIT_ASSERT(rng->generateRandom(testData, *k >> 3));
+                                       testData[0] &= 0x0F;
+                               }
+                               else
+                               {
+                                       CPPUNIT_ASSERT(true == false);
+                               }
+
+                               // Encrypt the data
+                               ByteString encryptedData;
+
+                               CPPUNIT_ASSERT(rsa->encrypt(kp->getPublicKey(), testData, encryptedData, *pad));
+
+                               // The encrypted data length should equal the modulus length
+                               CPPUNIT_ASSERT(encryptedData.size() == (*k >> 3));
+                               CPPUNIT_ASSERT(encryptedData != testData);
+
+                               // Now decrypt the data
+                               ByteString decryptedData;
+
+                               CPPUNIT_ASSERT(rsa->decrypt(kp->getPrivateKey(), encryptedData, decryptedData, *pad));
+
+                               // Check that the data was properly decrypted
+                               CPPUNIT_ASSERT(decryptedData == testData);
+                       }
+
+                       rsa->recycleKeyPair(kp);
+               }
+       }
+}
+
diff --git a/SoftHSMv2/src/lib/crypto/test/RSATests.h b/SoftHSMv2/src/lib/crypto/test/RSATests.h
new file mode 100644 (file)
index 0000000..ca5c86d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RSATests.h
+
+ Contains test cases to test the RSA class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RSATESTS_H
+#define _SOFTHSM_V2_RSATESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "AsymmetricAlgorithm.h"
+
+class RSATests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(RSATests);
+       CPPUNIT_TEST(testKeyGeneration);
+       CPPUNIT_TEST(testSerialisation);
+       CPPUNIT_TEST(testPKCS8);
+       CPPUNIT_TEST(testSigningVerifying);
+       CPPUNIT_TEST(testSignVerifyKnownVector);
+       CPPUNIT_TEST(testEncryptDecrypt);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testKeyGeneration();
+       void testSerialisation();
+       void testPKCS8();
+       void testSigningVerifying();
+       void testSignVerifyKnownVector();
+       void testEncryptDecrypt();
+
+       void setUp();
+       void tearDown();
+
+private:
+       // RSA instance
+       AsymmetricAlgorithm* rsa;
+};
+
+#endif // !_SOFTHSM_V2_RSATESTS_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/chisq.c b/SoftHSMv2/src/lib/crypto/test/chisq.c
new file mode 100644 (file)
index 0000000..3fe4f66
--- /dev/null
@@ -0,0 +1,144 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/*
+
+    Compute probability of measured Chi Square value.
+    
+    This code was developed by Gary Perlman of the Wang
+    Institute (full citation below) and has been minimally
+    modified for use in this program.
+    
+*/
+
+#include <math.h>
+
+/*HEADER
+       Module:       z.c
+       Purpose:      compute approximations to normal z distribution probabilities
+       Programmer:   Gary Perlman
+       Organization: Wang Institute, Tyngsboro, MA 01879
+       Copyright:    none
+       Tabstops:     4
+*/
+
+#define        Z_MAX          6.0            /* maximum meaningful z value */
+
+/*FUNCTION poz: probability of normal z value */
+/*ALGORITHM
+       Adapted from a polynomial approximation in:
+               Ibbetson D, Algorithm 209
+               Collected Algorithms of the CACM 1963 p. 616
+       Note:
+               This routine has six digit accuracy, so it is only useful for absolute
+               z values < 6.  For z values >= to 6.0, poz() returns 0.0.
+*/
+static double        /*VAR returns cumulative probability from -oo to z */
+poz(const double z)  /*VAR normal z value */
+{
+    double y, x, w;
+
+    if (z == 0.0) {
+       x = 0.0;
+    } else {
+       y = 0.5 * fabs(z);
+       if (y >= (Z_MAX * 0.5)) {
+           x = 1.0;
+       } else if (y < 1.0) {
+          w = y * y;
+          x = ((((((((0.000124818987 * w
+                  -0.001075204047) * w +0.005198775019) * w
+                  -0.019198292004) * w +0.059054035642) * w
+                  -0.151968751364) * w +0.319152932694) * w
+                  -0.531923007300) * w +0.797884560593) * y * 2.0;
+       } else {
+           y -= 2.0;
+           x = (((((((((((((-0.000045255659 * y
+                   +0.000152529290) * y -0.000019538132) * y
+                   -0.000676904986) * y +0.001390604284) * y
+                   -0.000794620820) * y -0.002034254874) * y
+                   +0.006549791214) * y -0.010557625006) * y
+                   +0.011630447319) * y -0.009279453341) * y
+                   +0.005353579108) * y -0.002141268741) * y
+                   +0.000535310849) * y +0.999936657524;
+       }
+    }
+    return (z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5));
+}
+
+/*
+       Module:       chisq.c
+       Purpose:      compute approximations to chisquare distribution probabilities
+       Contents:     pochisq()
+       Uses:         poz() in z.c (Algorithm 209)
+       Programmer:   Gary Perlman
+       Organization: Wang Institute, Tyngsboro, MA 01879
+       Copyright:    none
+       Tabstops:     4
+*/
+
+#define        LOG_SQRT_PI     0.5723649429247000870717135 /* log (sqrt (pi)) */
+#define        I_SQRT_PI       0.5641895835477562869480795 /* 1 / sqrt (pi) */
+#define        BIGX           20.0         /* max value to represent exp (x) */
+#define        ex(x)             (((x) < -BIGX) ? 0.0 : exp(x))
+
+/*FUNCTION pochisq: probability of chi sqaure value */
+/*ALGORITHM Compute probability of chi square value.
+       Adapted from:
+               Hill, I. D. and Pike, M. C.  Algorithm 299
+               Collected Algorithms for the CACM 1967 p. 243
+       Updated for rounding errors based on remark in
+               ACM TOMS June 1985, page 185
+*/
+
+double pochisq(
+       const double ax,    /* obtained chi-square value */
+       const int df        /* degrees of freedom */
+       )
+{
+    double x = ax;
+    double a, y, s;
+    double e, c, z;
+    int even;              /* true if df is an even number */
+
+    if (x <= 0.0 || df < 1) {
+       return 1.0;
+    }
+
+    a = 0.5 * x;
+    even = (2 * (df / 2)) == df;
+    y = 0.0;
+    if (df > 1) {
+       y = ex(-a);
+    }
+    s = (even ? y : (2.0 * poz(-sqrt(x))));
+    if (df > 2) {
+       x = 0.5 * (df - 1.0);
+       z = (even ? 1.0 : 0.5);
+       if (a > BIGX) {
+           e = (even ? 0.0 : LOG_SQRT_PI);
+           c = log(a);
+           while (z <= x) {
+               e = log(z) + e;
+               s += ex(c * z - a - e);
+               z += 1.0;
+           }
+           return (s);
+       } else {
+           e = (even ? 1.0 : (I_SQRT_PI / sqrt(a)));
+           c = 0.0;
+           while (z <= x) {
+                   e = e * (a / z);
+                   c = c + e;
+                   z += 1.0;
+           }
+           return (c * y + s);
+       }
+    } else {
+       return s;
+    }
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/cryptotest.cpp b/SoftHSMv2/src/lib/crypto/test/cryptotest.cpp
new file mode 100644 (file)
index 0000000..2fc7b8f
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ cryptotest.cpp
+
+ The main test executor for tests on the cryptographic functions 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;
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/ent.c b/SoftHSMv2/src/lib/crypto/test/ent.c
new file mode 100644 (file)
index 0000000..b255405
--- /dev/null
@@ -0,0 +1,110 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/*
+       ENT  --  Entropy calculation and analysis of putative
+                random sequences.
+
+        Designed and implemented by John "Random" Walker in May 1985.
+
+       Multiple analyses of random sequences added in December 1985.
+
+       Bit stream analysis added in September 1997.
+
+       Terse mode output, getopt() command line processing,
+       optional stdin input, and HTML documentation added in
+       October 1998.
+       
+       Documentation for the -t (terse output) option added
+       in July 2006.
+       
+       Replaced table look-up for chi square to probability
+       conversion with algorithmic computation in January 2008.
+
+       For additional information and the latest version,
+       see http://www.fourmilab.ch/random/
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "iso8859.h"
+#include "randtest.h"
+
+#define UPDATE  "January 28th, 2008"
+
+#define FALSE 0
+#define TRUE  1
+
+#ifdef M_PI
+#define PI      M_PI
+#else
+#define PI      3.14159265358979323846
+#endif
+
+extern double pochisq(const double ax, const int df);
+
+/*  Main program  */
+
+void doEnt
+(
+       unsigned char* data, 
+       size_t len, 
+       double* pEntropy,
+       double* pChiProbability,
+       double* pArithMean,
+       double* pMontePi,
+       double* pSerialCorrelation
+)
+{
+       size_t s;
+       long ccount[256];             /* Bins to count occurrences of values */
+       double montepi, chip,
+              scc, ent, mean, chisq;
+
+       /* Initialise for calculations */
+
+       rt_init(FALSE);
+
+       /* Scan input file and count character occurrences */
+
+       for (s = 0; s < len; s++)
+       {
+          unsigned char ocb = data[s];
+
+          ccount[ocb]++;             /* Update counter for this bin */
+          rt_add(&ocb, 1);
+       }
+
+       /* Complete calculation and return sequence metrics */
+
+       rt_end(&ent, &chisq, &mean, &montepi, &scc);
+
+       /* Calculate probability of observed distribution occurring from
+          the results of the Chi-Square test */
+
+       chip = pochisq(chisq, 255);
+
+       /* Print bin counts if requested */
+
+       /* Return calculated results */
+
+       *pEntropy = ent;
+       *pChiProbability = chip;
+       *pArithMean = mean;
+       *pMontePi = montepi;
+       *pSerialCorrelation = scc;
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/ent.h b/SoftHSMv2/src/lib/crypto/test/ent.h
new file mode 100644 (file)
index 0000000..5958888
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ ent.h
+
+ Header file to give access to the modified ent.c implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ENT_H
+#define _SOFTHSM_V2_ENT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void doEnt
+(
+       unsigned char* data, 
+       size_t len, 
+       double* pEntropy,
+       double* pChiProbability,
+       double* pArithMean,
+       double* pMontePi,
+       double* pSerialCorrelation
+);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // !_SOFTHSM_V2_ENT_H
+
diff --git a/SoftHSMv2/src/lib/crypto/test/iso8859.c b/SoftHSMv2/src/lib/crypto/test/iso8859.c
new file mode 100644 (file)
index 0000000..bed7244
--- /dev/null
@@ -0,0 +1,25 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/* ISO 8859/1 Latin-1 alphabetic and upper and lower case bit vector tables. */
+
+/* LINTLIBRARY */
+
+unsigned char isoalpha[32] = {
+    0,0,0,0,0,0,0,0,127,255,255,224,127,255,255,224,0,0,0,0,0,0,0,0,255,255,
+    254,255,255,255,254,255
+};
+
+unsigned char isoupper[32] = {
+    0,0,0,0,0,0,0,0,127,255,255,224,0,0,0,0,0,0,0,0,0,0,0,0,255,255,254,254,
+    0,0,0,0
+};
+
+unsigned char isolower[32] = {
+    0,0,0,0,0,0,0,0,0,0,0,0,127,255,255,224,0,0,0,0,0,0,0,0,0,0,0,1,255,255,
+    254,255
+};
diff --git a/SoftHSMv2/src/lib/crypto/test/iso8859.h b/SoftHSMv2/src/lib/crypto/test/iso8859.h
new file mode 100644 (file)
index 0000000..7462f15
--- /dev/null
@@ -0,0 +1,23 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/* ISO 8859/1 Latin-1 "ctype" macro replacements. */
+
+extern unsigned char isoalpha[32], isoupper[32], isolower[32];
+
+#define isISOspace(x)  ((isascii(((unsigned char) (x))) && isspace(((unsigned char) (x)))) || ((x) == 0xA0))
+#define isISOalpha(x)  ((isoalpha[(((unsigned char) (x))) / 8] & (0x80 >> ((((unsigned char) (x))) % 8))) != 0)
+#define isISOupper(x)  ((isoupper[(((unsigned char) (x))) / 8] & (0x80 >> ((((unsigned char) (x))) % 8))) != 0)
+#define isISOlower(x)  ((isolower[(((unsigned char) (x))) / 8] & (0x80 >> ((((unsigned char) (x))) % 8))) != 0)
+#define isISOprint(x)   ((((x) >= ' ') && ((x) <= '~')) || ((x) >= 0xA0))
+#define toISOupper(x)   (isISOlower(x) ? (isascii(((unsigned char) (x))) ?  \
+                            toupper(x) : (((((unsigned char) (x)) != 0xDF) && \
+                            (((unsigned char) (x)) != 0xFF)) ? \
+                           (((unsigned char) (x)) - 0x20) : (x))) : (x))
+#define toISOlower(x)   (isISOupper(x) ? (isascii(((unsigned char) (x))) ?  \
+                            tolower(x) : (((unsigned char) (x)) + 0x20)) \
+                           : (x))
diff --git a/SoftHSMv2/src/lib/crypto/test/randtest.c b/SoftHSMv2/src/lib/crypto/test/randtest.c
new file mode 100644 (file)
index 0000000..5a54737
--- /dev/null
@@ -0,0 +1,190 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/*
+
+        Apply various randomness tests to a stream of bytes
+
+                 by John Walker  --  September 1996
+                      http://www.fourmilab.ch/
+
+*/
+
+#include <math.h>
+
+#define FALSE 0
+#define TRUE  1
+
+#define log2of10 3.32192809488736234787
+
+static int binary = FALSE;        /* Treat input as a bitstream */
+
+static long ccount[256],          /* Bins to count occurrences of values */
+           totalc = 0;            /* Total bytes counted */
+static double prob[256];          /* Probabilities per bin for entropy */
+
+/*  RT_LOG2  --  Calculate log to the base 2  */
+
+static double rt_log2(double x)
+{
+    return log2of10 * log10(x);
+}
+
+#define MONTEN 6                     /* Bytes used as Monte Carlo
+                                        co-ordinates.  This should be no more
+                                        bits than the mantissa of your
+                                         "double" floating point type. */
+
+static int mp, sccfirst;
+static unsigned int monte[MONTEN];
+static long inmont, mcount;
+static double cexp, incirc, montex, montey, montepi,
+             scc, sccun, sccu0, scclast, scct1, scct2, scct3,
+             ent, chisq, datasum;
+
+/*  RT_INIT  --  Initialise random test counters.  */
+
+void rt_init(int binmode)
+{
+    int i;
+
+    binary = binmode;         /* Set binary / byte mode */
+
+    /* Initialise for calculations */
+
+    ent = 0.0;                /* Clear entropy accumulator */
+    chisq = 0.0;              /* Clear Chi-Square */
+    datasum = 0.0;            /* Clear sum of bytes for arithmetic mean */
+
+    mp = 0;                   /* Reset Monte Carlo accumulator pointer */
+    mcount = 0;               /* Clear Monte Carlo tries */
+    inmont = 0;               /* Clear Monte Carlo inside count */
+    incirc = 65535.0 * 65535.0;/* In-circle distance for Monte Carlo */
+
+    sccfirst = TRUE;          /* Mark first time for serial correlation */
+    scct1 = scct2 = scct3 = 0.0; /* Clear serial correlation terms */
+
+    incirc = pow(pow(256.0, (double) (MONTEN / 2)) - 1, 2.0);
+
+    for (i = 0; i < 256; i++) {
+       ccount[i] = 0;
+    }
+    totalc = 0;
+}
+
+/*  RT_ADD  -- Add one or more bytes to accumulation.  */
+
+void rt_add(void *buf, int bufl)
+{
+    unsigned char *bp = (unsigned char *)buf;
+    int oc, c, bean;
+
+    while (bean = 0, (bufl-- > 0)) {
+       oc = *bp++;
+
+       do {
+         if (binary) {
+            c = !!(oc & 0x80);
+         } else {
+            c = oc;
+         }
+         ccount[c]++;            /* Update counter for this bin */
+         totalc++;
+
+         /* Update inside / outside circle counts for Monte Carlo
+            computation of PI */
+
+         if (bean == 0) {
+             monte[mp++] = oc;       /* Save character for Monte Carlo */
+             if (mp >= MONTEN) {     /* Calculate every MONTEN character */
+                int mj;
+
+                mp = 0;
+                mcount++;
+                montex = montey = 0;
+                for (mj = 0; mj < MONTEN / 2; mj++) {
+                   montex = (montex * 256.0) + monte[mj];
+                   montey = (montey * 256.0) + monte[(MONTEN / 2) + mj];
+                }
+                if ((montex * montex + montey *  montey) <= incirc) {
+                   inmont++;
+                }
+             }
+         }
+
+         /* Update calculation of serial correlation coefficient */
+
+         sccun = c;
+         if (sccfirst) {
+            sccfirst = FALSE;
+            scclast = 0;
+            sccu0 = sccun;
+         } else {
+            scct1 = scct1 + scclast * sccun;
+         }
+         scct2 = scct2 + sccun;
+         scct3 = scct3 + (sccun * sccun);
+         scclast = sccun;
+         oc <<= 1;
+       } while (binary && (++bean < 8));
+    }
+}
+
+/*  RT_END  -- Complete calculation and return results.  */
+
+void rt_end(double *r_ent, double *r_chisq, double *r_mean,
+           double *r_montepicalc, double *r_scc)
+{
+    int i;
+
+    /* Complete calculation of serial correlation coefficient */
+
+    scct1 = scct1 + scclast * sccu0;
+    scct2 = scct2 * scct2;
+    scc = totalc * scct3 - scct2;
+    if (scc == 0.0) {
+       scc = -100000;
+    } else {
+       scc = (totalc * scct1 - scct2) / scc;
+    }
+
+    /* Scan bins and calculate probability for each bin and
+       Chi-Square distribution.  The probability will be reused
+       in the entropy calculation below.  While we're at it,
+       we sum of all the data which will be used to compute the
+       mean. */
+       
+    cexp = totalc / (binary ? 2.0 : 256.0);  /* Expected count per bin */
+    for (i = 0; i < (binary ? 2 : 256); i++) {
+       double a = ccount[i] - cexp;;
+       
+       prob[i] = ((double) ccount[i]) / totalc;       
+       chisq += (a * a) / cexp;
+       datasum += ((double) i) * ccount[i];
+    }
+
+    /* Calculate entropy */
+
+    for (i = 0; i < (binary ? 2 : 256); i++) {
+       if (prob[i] > 0.0) {
+         ent += prob[i] * rt_log2(1 / prob[i]);
+       }
+    }
+
+    /* Calculate Monte Carlo value for PI from percentage of hits
+       within the circle */
+
+    montepi = 4.0 * (((double) inmont) / mcount);
+
+    /* Return results through arguments */
+
+    *r_ent = ent;
+    *r_chisq = chisq;
+    *r_mean = datasum / totalc;
+    *r_montepicalc = montepi;
+    *r_scc = scc;
+}
diff --git a/SoftHSMv2/src/lib/crypto/test/randtest.h b/SoftHSMv2/src/lib/crypto/test/randtest.h
new file mode 100644 (file)
index 0000000..53bef35
--- /dev/null
@@ -0,0 +1,13 @@
+/* This code was taken from http://www.fourmilab.ch/random/ where it states that:
+
+   This software is in the public domain. Permission to use, copy, modify, and distribute 
+   this software and its documentation for any purpose and without fee is hereby granted, 
+   without any conditions or restrictions. This software is provided “as is” without 
+   express or implied warranty. */
+
+/*  Random test function prototypes  */
+
+extern void rt_init(int binmode);
+extern void rt_add(void *buf, int bufl);
+extern void rt_end(double *r_ent, double *r_chisq, double *r_mean,
+                   double *r_montepicalc, double *r_scc);
diff --git a/SoftHSMv2/src/lib/data_mgr/ByteString.cpp b/SoftHSMv2/src/lib/data_mgr/ByteString.cpp
new file mode 100644 (file)
index 0000000..e133f71
--- /dev/null
@@ -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 (file)
index 0000000..2c2ef33
--- /dev/null
@@ -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 (file)
index 0000000..85aa4d7
--- /dev/null
@@ -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 (file)
index 0000000..9ea23bd
--- /dev/null
@@ -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 (file)
index 0000000..7967ef6
--- /dev/null
@@ -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 (file)
index 0000000..71dc80c
--- /dev/null
@@ -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 (file)
index 0000000..987e76b
--- /dev/null
@@ -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 (file)
index 0000000..93d99bc
--- /dev/null
@@ -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 (file)
index 0000000..57de156
--- /dev/null
@@ -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 (file)
index 0000000..6c73369
--- /dev/null
@@ -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 (file)
index 0000000..0bd4238
--- /dev/null
@@ -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 (file)
index 0000000..cfd92fe
--- /dev/null
@@ -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 (file)
index 0000000..1c635a4
--- /dev/null
@@ -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 (file)
index 0000000..b1dd967
--- /dev/null
@@ -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 (file)
index 0000000..e1ebcdd
--- /dev/null
@@ -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 (file)
index 0000000..6fcfd94
--- /dev/null
@@ -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 (file)
index 0000000..4663626
--- /dev/null
@@ -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 (file)
index 0000000..7ef4816
--- /dev/null
@@ -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 (file)
index 0000000..743a01b
--- /dev/null
@@ -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 (file)
index 0000000..49fa535
--- /dev/null
@@ -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;
+}
diff --git a/SoftHSMv2/src/lib/handle_mgr/Handle.cpp b/SoftHSMv2/src/lib/handle_mgr/Handle.cpp
new file mode 100644 (file)
index 0000000..127b4c7
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ Handle.h
+
+ This class represents a single handle
+ *****************************************************************************/
+
+#include "Handle.h"
+
+// Constructor
+Handle::Handle(CK_HANDLE_KIND _kind, CK_SLOT_ID _slotID, CK_SESSION_HANDLE _hSession)
+    : kind(_kind), slotID(_slotID), hSession(_hSession), object(NULL_PTR), isPrivate(false)
+{
+}
+
+Handle::Handle(CK_HANDLE_KIND _kind, CK_SLOT_ID _slotID)
+    : kind(_kind), slotID(_slotID), hSession(CK_INVALID_HANDLE), object(NULL_PTR), isPrivate(false)
+{
+}
+
+Handle::Handle()
+    : kind(CKH_INVALID), slotID(0), hSession(CK_INVALID_HANDLE), object(NULL_PTR), isPrivate(false)
+{
+
+}
diff --git a/SoftHSMv2/src/lib/handle_mgr/Handle.h b/SoftHSMv2/src/lib/handle_mgr/Handle.h
new file mode 100644 (file)
index 0000000..94b42f9
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ Handle.h
+
+ This class represents a single handle
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HANDLE_H
+#define _SOFTHSM_V2_HANDLE_H
+
+#include "cryptoki.h"
+
+enum {
+   CKH_INVALID,
+   CKH_SESSION,
+   CKH_OBJECT
+};
+
+#define CK_HANDLE_KIND CK_ULONG
+
+class Handle
+{
+public:
+    Handle(CK_HANDLE_KIND kind, CK_SLOT_ID slotID, CK_SESSION_HANDLE hSession);
+    Handle(CK_HANDLE_KIND kind, CK_SLOT_ID slotID);
+    Handle();
+
+    CK_HANDLE_KIND kind;
+    CK_SLOT_ID slotID;
+    CK_SESSION_HANDLE hSession;
+
+    CK_VOID_PTR object;
+    bool isPrivate;
+};
+
+#endif // !_SOFTHSM_V2_HANDLE_H
+
diff --git a/SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp b/SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp
new file mode 100644 (file)
index 0000000..ccf42d0
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+
+/*****************************************************************************
+ HandleManager.cpp
+
+ One of the most difficult problems to track down is when stale cryptoki handles
+ for e.g. keys, objects and sessions get reused by a misbehaving application.
+ Especialy when handles that became invalid have since been reused.
+ A simple solution to this is to never reuse a handle once it has been issued
+ and subsequently invalidated.
+
+ The handle manager tracks issued handles along with what kind of object
+ is presented by the handle and an actual pointer to the object in question.
+
+ Issued handles are unique per application run. All session and object handles
+ use the same handle manager and therefore there will never be e.g. a session
+ with the same handle as an object.
+
+ *****************************************************************************/
+
+#include "HandleManager.h"
+#include "log.h"
+
+// Constructor
+HandleManager::HandleManager()
+{
+       handlesMutex = MutexFactory::i()->getMutex();
+       handleCounter = 0;
+}
+
+// Destructor
+HandleManager::~HandleManager()
+{
+
+       MutexFactory::i()->recycleMutex(handlesMutex);
+}
+
+CK_SESSION_HANDLE HandleManager::addSession(CK_SLOT_ID slotID, CK_VOID_PTR session)
+{
+       MutexLocker lock(handlesMutex);
+
+       Handle h( CKH_SESSION, slotID );
+       h.object = session;
+       handles[++handleCounter] = h;
+       return (CK_SESSION_HANDLE)handleCounter;
+}
+
+CK_VOID_PTR HandleManager::getSession(const CK_SESSION_HANDLE hSession)
+{
+       MutexLocker lock(handlesMutex);
+
+       std::map< CK_ULONG, Handle>::iterator it = handles.find(hSession);
+       if (it == handles.end() || CKH_SESSION != it->second.kind)
+               return NULL_PTR;
+       return it->second.object;
+}
+
+CK_OBJECT_HANDLE HandleManager::addSessionObject(CK_SLOT_ID slotID, CK_SESSION_HANDLE hSession, bool isPrivate, CK_VOID_PTR object)
+{
+       MutexLocker lock(handlesMutex);
+
+       // Return existing handle when the object has already been registered.
+       std::map< CK_VOID_PTR, CK_ULONG>::iterator oit = objects.find(object);
+       if (oit != objects.end()) {
+               std::map< CK_ULONG, Handle>::iterator hit = handles.find(oit->second);
+               if (hit == handles.end() || CKH_OBJECT != hit->second.kind || slotID != hit->second.slotID) {
+                       objects.erase(oit);
+                       return CK_INVALID_HANDLE;
+               } else
+                       return oit->second;
+       }
+
+       Handle h( CKH_OBJECT, slotID, hSession );
+       h.isPrivate = isPrivate;
+       h.object = object;
+       handles[++handleCounter] = h;
+       objects[object] = handleCounter;
+       return (CK_OBJECT_HANDLE)handleCounter;
+}
+
+CK_OBJECT_HANDLE HandleManager::addTokenObject(CK_SLOT_ID slotID, bool isPrivate, CK_VOID_PTR object)
+{
+       MutexLocker lock(handlesMutex);
+
+       // Return existing handle when the object has already been registered.
+       std::map< CK_VOID_PTR, CK_ULONG>::iterator oit = objects.find(object);
+       if (oit != objects.end()) {
+               std::map< CK_ULONG, Handle>::iterator hit = handles.find(oit->second);
+               if (hit == handles.end() || CKH_OBJECT != hit->second.kind || slotID != hit->second.slotID) {
+                       objects.erase(oit);
+                       return CK_INVALID_HANDLE;
+               } else
+                       return oit->second;
+       }
+
+       // Token objects are not associated with a specific session.
+       Handle h( CKH_OBJECT, slotID );
+       h.isPrivate = isPrivate;
+       h.object = object;
+       handles[++handleCounter] = h;
+       objects[object] = handleCounter;
+       return (CK_OBJECT_HANDLE)handleCounter;
+}
+
+CK_VOID_PTR HandleManager::getObject(const CK_OBJECT_HANDLE hObject)
+{
+       MutexLocker lock(handlesMutex);
+
+       std::map< CK_ULONG, Handle>::iterator it = handles.find(hObject);
+       if (it == handles.end() || CKH_OBJECT != it->second.kind )
+               return NULL_PTR;
+       return it->second.object;
+}
+
+CK_OBJECT_HANDLE HandleManager::getObjectHandle(CK_VOID_PTR object)
+{
+       MutexLocker lock(handlesMutex);
+
+       std::map< CK_VOID_PTR, CK_ULONG>::iterator it = objects.find(object);
+       if (it == objects.end())
+               return CK_INVALID_HANDLE;
+       return it->second;
+}
+
+void HandleManager::destroyObject(const CK_OBJECT_HANDLE hObject)
+{
+       MutexLocker lock(handlesMutex);
+
+       std::map< CK_ULONG, Handle>::iterator it = handles.find(hObject);
+       if (it != handles.end() && CKH_OBJECT == it->second.kind) {
+               objects.erase(it->second.object);
+               handles.erase(it);
+       }
+}
+
+void HandleManager::sessionClosed(const CK_SESSION_HANDLE hSession)
+{
+       CK_SLOT_ID slotID;
+       {
+               MutexLocker lock(handlesMutex);
+
+               std::map< CK_ULONG, Handle>::iterator it = handles.find(hSession);
+               if (it == handles.end() || CKH_SESSION != it->second.kind)
+                       return; // Unable to find the specified session.
+
+               slotID = it->second.slotID;
+
+               // session closed, so we can erase information about it.
+               handles.erase(it);
+
+               // Erase all session object handles associated with the given session handle.
+               CK_ULONG openSessionCount = 0;
+               for (it = handles.begin(); it != handles.end(); ) {
+                       Handle &h = it->second;
+                       if (CKH_SESSION == h.kind && slotID == h.slotID) {
+                               ++openSessionCount; // another session is open for this slotID.
+                       } else {
+                               if (CKH_OBJECT == h.kind && hSession == h.hSession) {
+                                       // A session object is present for the given session, so erase it.
+                                       objects.erase(it->second.object);
+                                       // Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
+                                       handles.erase(it++);
+                                       continue;
+                               }
+                       }
+                       ++it;
+               }
+
+                // We are done when there are still sessions open.
+               if (openSessionCount)
+                       return;
+       }
+
+       // No more sessions open for this token, so remove all object handles that are still valid for the given slotID.
+       allSessionsClosed(slotID);
+}
+
+void HandleManager::allSessionsClosed(const CK_SLOT_ID slotID)
+{
+       MutexLocker lock(handlesMutex);
+
+       // Erase all "session", "session object" and "token object" handles for a given slot id.
+       std::map< CK_ULONG, Handle>::iterator it;
+       for (it = handles.begin(); it != handles.end(); ) {
+               Handle &h = it->second;
+               if (slotID == h.slotID) {
+                       if (CKH_OBJECT == it->second.kind)
+                               objects.erase(it->second.object);
+                       // Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
+                       handles.erase(it++);
+                       continue;
+               }
+               ++it;
+       }
+}
+
+void HandleManager::tokenLoggedOut(const CK_SLOT_ID slotID)
+{
+       MutexLocker lock(handlesMutex);
+
+       // Erase all private "token object" or "session object" handles for a given slot id.
+       std::map< CK_ULONG, Handle>::iterator it;
+       for (it = handles.begin(); it != handles.end(); ) {
+               Handle &h = it->second;
+               if (CKH_OBJECT == h.kind && slotID == h.slotID && h.isPrivate) {
+                       // A private object is present for the given slotID so we need to remove it.
+                       objects.erase(it->second.object);
+                       // Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
+                       handles.erase(it++);
+                       continue;
+               }
+               ++it;
+       }
+}
diff --git a/SoftHSMv2/src/lib/handle_mgr/HandleManager.h b/SoftHSMv2/src/lib/handle_mgr/HandleManager.h
new file mode 100644 (file)
index 0000000..e85e628
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ HandleManager.h
+
+ Keeps track of the issued cryptoki handles within SoftHSM
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HANDLEMANAGER_H
+#define _SOFTHSM_V2_HANDLEMANAGER_H
+
+#include "MutexFactory.h"
+#include "Handle.h"
+#include "cryptoki.h"
+
+#include <map>
+
+#define CK_INTERNAL_SESSION_HANDLE CK_SESSION_HANDLE
+
+class HandleManager
+{
+public:
+    HandleManager();
+
+    virtual ~HandleManager();
+
+    CK_SESSION_HANDLE addSession(CK_SLOT_ID slotID, CK_VOID_PTR session);
+    CK_VOID_PTR getSession(const CK_SESSION_HANDLE hSession);
+
+    // Add the session object and return a handle. For objects that have already been registered, check that the
+    // slotID matches. The hSession may be different as the object may be added as part of a find objects operation.
+    CK_OBJECT_HANDLE addSessionObject(CK_SLOT_ID slotID, CK_SESSION_HANDLE hSession, bool isPrivate, CK_VOID_PTR object);
+
+    // Add the token object and return a handle. For objects that have already been registered, check that the
+    // slotID mathces.
+    CK_OBJECT_HANDLE addTokenObject(CK_SLOT_ID slotID, bool isPrivate, CK_VOID_PTR object);
+
+    // Get the object pointer associated with the given object handle.
+    CK_VOID_PTR getObject(const CK_OBJECT_HANDLE hObject);
+
+    // Get the object handle for the object pointer that has been previously registered.
+    // When the object is not found CK_INVALID_HANDLE is returned.
+    CK_OBJECT_HANDLE getObjectHandle(CK_VOID_PTR object);
+
+    // Remove the given object handle.
+    void destroyObject(const CK_OBJECT_HANDLE hObject);
+
+    // Remove the given session handle and all session object handles for the session.
+    // The token object handles retrieved using the session will remain valid unless
+    // this is the last session of a token being closed. In that case remove all token
+    // object handles for the slot/token associated with the session.
+    void sessionClosed(const CK_SESSION_HANDLE hSession);
+
+    // Remove all session and object handles for the given slotID.
+    // All handles for the given slotID will become invalid.
+    void allSessionsClosed(const CK_SLOT_ID slotID);
+
+    // Remove all handles to private objects for the given slotID.
+    // All handles to public objects for the given slotID remain valid.
+    void tokenLoggedOut(const CK_SLOT_ID slotID);
+
+private:
+    Mutex* handlesMutex;
+    std::map< CK_ULONG, Handle> handles;
+    std::map< CK_VOID_PTR, CK_ULONG> objects;
+    CK_ULONG handleCounter;
+};
+
+#endif // !_SOFTHSM_V2_HANDLEMANAGER_H
+
diff --git a/SoftHSMv2/src/lib/handle_mgr/Makefile.am b/SoftHSMv2/src/lib/handle_mgr/Makefile.am
new file mode 100644 (file)
index 0000000..108f74d
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES =                         $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                          -I$(srcdir)/.. \
+                                       -I$(srcdir)/../common \
+                                       -I$(srcdir)/../crypto \
+                                       -I$(srcdir)/../data_mgr \
+                                       -I$(srcdir)/../object_store \
+                                       -I$(srcdir)/../pkcs11 \
+                                       -I$(srcdir)/../slot_mgr
+
+noinst_LTLIBRARIES =                   libsofthsm_handlemgr.la
+libsofthsm_handlemgr_la_SOURCES =      HandleManager.cpp \
+                                       Handle.cpp
+
+SUBDIRS =                              test
+
+EXTRA_DIST =                           $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.cpp b/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.cpp
new file mode 100644 (file)
index 0000000..fbf0403
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ HandleManagerTests.cpp
+
+ Contains test cases to test the handle manager implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "HandleManagerTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HandleManagerTests);
+
+void HandleManagerTests::setUp()
+{
+       handleManager = new HandleManager();
+}
+
+void HandleManagerTests::tearDown()
+{
+       delete handleManager;
+}
+
+void HandleManagerTests::testHandleManager()
+{
+       CPPUNIT_ASSERT(handleManager != NULL);
+
+       CK_SLOT_ID slotID = 1234; // we need a unique value
+       CK_SESSION_HANDLE hSession;
+       CK_VOID_PTR session = &hSession; // we need a unique value
+       CK_SESSION_HANDLE hSession2;
+       CK_VOID_PTR session2 = &hSession2; // we need a unique value
+       CK_OBJECT_HANDLE hObject;
+       CK_VOID_PTR object = &hObject; // we need a unique value
+       CK_OBJECT_HANDLE hObject2;
+       CK_VOID_PTR object2 = &hObject2; // we need a unique value
+       CK_OBJECT_HANDLE hObject3;
+       CK_VOID_PTR object3 = &hObject3; // we need a unique value
+       CK_OBJECT_HANDLE hObject4;
+       CK_VOID_PTR object4 = &hObject4; // we need a unique value
+       CK_OBJECT_HANDLE hObject5;
+       CK_VOID_PTR object5 = &hObject5; // we need a unique value
+
+       // Check session object management.
+       hSession = handleManager->addSession(slotID, session);
+       CPPUNIT_ASSERT(hSession != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session == handleManager->getSession(hSession));
+       CPPUNIT_ASSERT_NO_THROW(handleManager->sessionClosed(123124));
+       handleManager->sessionClosed(hSession);
+       CPPUNIT_ASSERT(NULL == handleManager->getSession(hSession));
+
+       // Add an object, hSession doesn't have to exists
+       hObject = handleManager->addSessionObject(slotID, 4412412, true, object);
+       CPPUNIT_ASSERT(hObject != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object == handleManager->getObject(hObject));
+       handleManager->sessionClosed(4412412);
+       // Object still exists as the hSession was invalid
+       CPPUNIT_ASSERT(object == handleManager->getObject(hObject));
+       handleManager->allSessionsClosed(slotID);
+       // Object is now gone as all sessions for the given slotID have been removed.
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject));
+
+       // Add an object and then destroy it.
+       hObject = handleManager->addSessionObject(slotID, 4412412, true, object);
+       CPPUNIT_ASSERT(hObject != CK_INVALID_HANDLE);
+       handleManager->destroyObject(hObject);
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject));
+
+       hObject = handleManager->addTokenObject(slotID, false, object);
+       CPPUNIT_ASSERT(hObject != CK_INVALID_HANDLE);
+       handleManager->destroyObject(hObject);
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject));
+
+       // Create a valid session again
+       hSession = handleManager->addSession(slotID, session);
+       CPPUNIT_ASSERT(hSession != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session == handleManager->getSession(hSession));
+
+       // Now some magic with a couple of objects
+       // First add a public object
+       hObject = handleManager->addTokenObject(slotID, false, object);
+       CPPUNIT_ASSERT(hObject != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object == handleManager->getObject(hObject));
+
+       // Now add a private object
+       hObject2 = handleManager->addTokenObject(slotID, true, object2);
+       CPPUNIT_ASSERT(hObject2 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object2 == handleManager->getObject(hObject2));
+
+       // Now add another private object
+       hObject3 = handleManager->addTokenObject(slotID, true, object3);
+       CPPUNIT_ASSERT(hObject3 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object3 == handleManager->getObject(hObject3));
+
+       // Adding the same object will return the same handle whether the object is marked private or public.
+       CPPUNIT_ASSERT(hObject2 == handleManager->addTokenObject(slotID, true, object2));
+       // Because the private state of an object cannot be changed it won't be marked as public, it remains private
+       CPPUNIT_ASSERT(hObject2 == handleManager->addTokenObject(slotID, false, object2));
+
+       // It is not allowed to migrate an object from one slot to another, so here we return an invalid handle.
+       CPPUNIT_ASSERT(CK_INVALID_HANDLE == handleManager->addTokenObject(124121, false, object2));
+
+       // Now add another private session object
+       hObject4 = handleManager->addSessionObject(slotID, hSession, true, object4);
+       CPPUNIT_ASSERT(hObject4 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object4 == handleManager->getObject(hObject4));
+
+       // Now add another public session object
+       hObject5 = handleManager->addSessionObject(slotID, hSession, false, object5);
+       CPPUNIT_ASSERT(hObject5 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(object5 == handleManager->getObject(hObject5));
+
+       // Logout, now private objects should be gone.
+       handleManager->tokenLoggedOut(slotID);
+       CPPUNIT_ASSERT(object == handleManager->getObject(hObject));
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject2)); // should still be private and removed.
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject3));
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject4));
+       CPPUNIT_ASSERT(object5 == handleManager->getObject(hObject5));
+
+       // Create another valid session for the slot
+       hSession2 = handleManager->addSession(slotID, session2);
+       CPPUNIT_ASSERT(hSession2 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session2 == handleManager->getSession(hSession2));
+
+       handleManager->sessionClosed(hSession);
+       CPPUNIT_ASSERT(object == handleManager->getObject(hObject)); // token object should still be there.
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject5)); // session object should be gone.
+
+       // Removing the last remaining session should kill the remaining handle.
+       handleManager->sessionClosed(hSession2);
+       CPPUNIT_ASSERT(NULL == handleManager->getObject(hObject)); // should be gone now.
+
+       CPPUNIT_ASSERT(NULL == handleManager->getSession(hSession));
+       CPPUNIT_ASSERT(NULL == handleManager->getSession(hSession2));
+
+
+       // Create a valid session again
+       hSession = handleManager->addSession(slotID, session);
+       CPPUNIT_ASSERT(hSession != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session == handleManager->getSession(hSession));
+
+       // Create another valid session for the slot
+       hSession2 = handleManager->addSession(slotID, session2);
+       CPPUNIT_ASSERT(hSession2 != CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session2 == handleManager->getSession(hSession2));
+
+       handleManager->allSessionsClosed(slotID);
+
+       CPPUNIT_ASSERT(NULL == handleManager->getSession(hSession));
+       CPPUNIT_ASSERT(NULL == handleManager->getSession(hSession2));
+}
diff --git a/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.h b/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.h
new file mode 100644 (file)
index 0000000..02022e4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ HandleManagerTests.h
+
+ Contains test cases to test the handle manager implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_HANDLEMANAGERTESTS_H
+#define _SOFTHSM_V2_HANDLEMANAGERTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "RNG.h"
+#include "HandleManager.h"
+
+class HandleManagerTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(HandleManagerTests);
+       CPPUNIT_TEST(testHandleManager);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testHandleManager();
+
+       void setUp();
+       void tearDown();
+
+private:
+       HandleManager *handleManager;
+
+};
+
+#endif // !_SOFTHSM_V2_HANDLEMANAGERTESTS_H
+
diff --git a/SoftHSMv2/src/lib/handle_mgr/test/Makefile.am b/SoftHSMv2/src/lib/handle_mgr/test/Makefile.am
new file mode 100644 (file)
index 0000000..8d110b0
--- /dev/null
@@ -0,0 +1,26 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../.. \
+                               -I$(srcdir)/../../common \
+                               -I$(srcdir)/../../crypto \
+                               -I$(srcdir)/../../data_mgr \
+                               -I$(srcdir)/../../object_store \
+                               -I$(srcdir)/../../pkcs11 \
+                               -I$(srcdir)/../../session_mgr \
+                               -I$(srcdir)/../../slot_mgr \
+                               @CPPUNIT_CFLAGS@
+
+check_PROGRAMS =               handlemgrtest
+
+handlemgrtest_SOURCES =                handlemgrtest.cpp \
+                               HandleManagerTests.cpp
+
+handlemgrtest_LDADD =          ../../libsofthsm_convarch.la 
+
+handlemgrtest_LDFLAGS =        @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install
+
+TESTS =                        handlemgrtest
+
+EXTRA_DIST =                   $(srcdir)/*.h
+
diff --git a/SoftHSMv2/src/lib/handle_mgr/test/handlemgrtest.cpp b/SoftHSMv2/src/lib/handle_mgr/test/handlemgrtest.cpp
new file mode 100644 (file)
index 0000000..eedb407
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ handlemgrtest.cpp
+
+ The main test executor for tests on the handle 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"
+
+#ifdef HAVE_CXX11
+std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr);
+#else
+std::auto_ptr<MutexFactory> MutexFactory::instance(NULL);
+#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();
+
+       return result.wasSuccessful() ? 0 : 1;
+}
diff --git a/SoftHSMv2/src/lib/main.cpp b/SoftHSMv2/src/lib/main.cpp
new file mode 100644 (file)
index 0000000..2dfd0eb
--- /dev/null
@@ -0,0 +1,1187 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ main.cpp
+
+ This file contains the main entry point to the PKCS #11 library. All it does
+ is dispatch calls to the actual implementation and check for fatal exceptions
+ on the boundary of the library.
+ *****************************************************************************/
+
+// The functions are exported library/DLL entry points
+#define CRYPTOKI_EXPORTS
+
+#include "config.h"
+#include "log.h"
+#include "fatal.h"
+#include "cryptoki.h"
+#include "SoftHSM.h"
+
+#if defined(__GNUC__) && \
+       (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) || \
+       defined(__SUNPRO_C) && __SUNPRO_C >= 0x590
+#define PKCS_API __attribute__ ((visibility("default")))
+#else
+#define PKCS_API
+#endif
+
+// PKCS #11 function list
+static CK_FUNCTION_LIST functionList =
+{
+       // Version information
+       { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
+       // Function pointers
+       C_Initialize,
+       C_Finalize,
+       C_GetInfo,
+       C_GetFunctionList,
+       C_GetSlotList,
+       C_GetSlotInfo,
+       C_GetTokenInfo,
+       C_GetMechanismList,
+       C_GetMechanismInfo,
+       C_InitToken,
+       C_InitPIN,
+       C_SetPIN,
+       C_OpenSession,
+       C_CloseSession,
+       C_CloseAllSessions,
+       C_GetSessionInfo,
+       C_GetOperationState,
+       C_SetOperationState,
+       C_Login,
+       C_Logout,
+       C_CreateObject,
+       C_CopyObject,
+       C_DestroyObject,
+       C_GetObjectSize,
+       C_GetAttributeValue,
+       C_SetAttributeValue,
+       C_FindObjectsInit,
+       C_FindObjects,
+       C_FindObjectsFinal,
+       C_EncryptInit,
+       C_Encrypt,
+       C_EncryptUpdate,
+       C_EncryptFinal,
+       C_DecryptInit,
+       C_Decrypt,
+       C_DecryptUpdate,
+       C_DecryptFinal,
+       C_DigestInit,
+       C_Digest,
+       C_DigestUpdate,
+       C_DigestKey,
+       C_DigestFinal,
+       C_SignInit,
+       C_Sign,
+       C_SignUpdate,
+       C_SignFinal,
+       C_SignRecoverInit,
+       C_SignRecover,
+       C_VerifyInit,
+       C_Verify,
+       C_VerifyUpdate,
+       C_VerifyFinal,
+       C_VerifyRecoverInit,
+       C_VerifyRecover,
+       C_DigestEncryptUpdate,
+       C_DecryptDigestUpdate,
+       C_SignEncryptUpdate,
+       C_DecryptVerifyUpdate,
+       C_GenerateKey,
+       C_GenerateKeyPair,
+       C_WrapKey,
+       C_UnwrapKey,
+       C_DeriveKey,
+       C_SeedRandom,
+       C_GenerateRandom,
+       C_GetFunctionStatus,
+       C_CancelFunction,
+       C_WaitForSlotEvent
+};
+
+// PKCS #11 initialisation function
+PKCS_API CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
+{
+       try
+       {
+               return SoftHSM::i()->C_Initialize(pInitArgs);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// PKCS #11 finalisation function
+PKCS_API CK_RV C_Finalize(CK_VOID_PTR pReserved)
+{
+       try
+       {
+               return SoftHSM::i()->C_Finalize(pReserved);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return information about the PKCS #11 module
+PKCS_API CK_RV C_GetInfo(CK_INFO_PTR pInfo)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetInfo(pInfo);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return the list of PKCS #11 functions
+PKCS_API CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
+{
+       try
+       {
+               if (ppFunctionList == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+               *ppFunctionList = &functionList;
+
+               return CKR_OK;
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return a list of available slots
+PKCS_API CK_RV C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetSlotList(tokenPresent, pSlotList, pulCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return information about a slot
+PKCS_API CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetSlotInfo(slotID, pInfo);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return information about a token in a slot
+PKCS_API CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetTokenInfo(slotID, pInfo);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return the list of supported mechanisms for a given slot
+PKCS_API CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetMechanismList(slotID, pMechanismList, pulCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Return more information about a mechanism for a given slot
+PKCS_API CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetMechanismInfo(slotID, type, pInfo);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise the token in the specified slot
+PKCS_API CK_RV C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel)
+{
+       try
+       {
+               return SoftHSM::i()->C_InitToken(slotID, pPin, ulPinLen, pLabel);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise the user PIN
+PKCS_API CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_InitPIN(hSession, pPin, ulPinLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Change the PIN
+PKCS_API CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SetPIN(hSession, pOldPin, ulOldLen, pNewPin, ulNewLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Open a new session to the specified slot
+PKCS_API CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_OpenSession(slotID, flags, pApplication, notify, phSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Close the given session
+PKCS_API CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_CloseSession(hSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Close all open sessions
+PKCS_API CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
+{
+       try
+       {
+               return SoftHSM::i()->C_CloseAllSessions(slotID);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Retrieve information about the specified session
+PKCS_API CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetSessionInfo(hSession, pInfo);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Determine the state of a running operation in a session
+PKCS_API CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetOperationState(hSession, pOperationState, pulOperationStateLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Set the operation sate in a session
+PKCS_API CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_SetOperationState(hSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Login on the token in the specified session
+PKCS_API CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Login(hSession, userType, pPin, ulPinLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Log out of the token in the specified session
+PKCS_API CK_RV C_Logout(CK_SESSION_HANDLE hSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_Logout(hSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Create a new object on the token in the specified session using the given attribute template
+PKCS_API CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_CreateObject(hSession, pTemplate, ulCount, phObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Create a copy of the object with the specified handle
+PKCS_API CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_CopyObject(hSession, hObject, pTemplate, ulCount, phNewObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Destroy the specified object
+PKCS_API CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_DestroyObject(hSession, hObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Determine the size of the specified object
+PKCS_API CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetObjectSize(hSession, hObject, pulSize);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Retrieve the specified attributes for the given object
+PKCS_API CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetAttributeValue(hSession, hObject, pTemplate, ulCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Change or set the value of the specified attributes on the specified object
+PKCS_API CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_SetAttributeValue(hSession, hObject, pTemplate, ulCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise object search in the specified session using the specified attribute template as search parameters
+PKCS_API CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_FindObjectsInit(hSession, pTemplate, ulCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Continue the search for objects in the specified session
+PKCS_API CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
+{
+       try
+       {
+               return SoftHSM::i()->C_FindObjects(hSession, phObject, ulMaxObjectCount, pulObjectCount);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finish searching for objects
+PKCS_API CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_FindObjectsFinal(hSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise encryption using the specified object and mechanism
+PKCS_API CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_EncryptInit(hSession, pMechanism, hObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Perform a single operation encryption operation in the specified session
+PKCS_API CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Encrypt(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Feed data to the running encryption operation in a session
+PKCS_API CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finalise the encryption operation
+PKCS_API CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_EncryptFinal(hSession, pEncryptedData, pulEncryptedDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise decryption using the specified object
+PKCS_API CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_DecryptInit(hSession, pMechanism, hObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Perform a single operation decryption in the given session
+PKCS_API CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Feed data to the running decryption operation in a session
+PKCS_API CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DecryptUpdate(hSession, pEncryptedData, ulEncryptedDataLen, pData, pDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finalise the decryption operation
+PKCS_API CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DecryptFinal(hSession, pData, pDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise digesting using the specified mechanism in the specified session
+PKCS_API CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
+{
+       try
+       {
+               return SoftHSM::i()->C_DigestInit(hSession, pMechanism);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Digest the specified data in a one-pass operation and return the resulting digest
+PKCS_API CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Digest(hSession, pData, ulDataLen, pDigest, pulDigestLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running digest operation
+PKCS_API CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DigestUpdate(hSession, pPart, ulPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running digest operation by digesting a secret key with the specified handle
+PKCS_API CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
+{
+       try
+       {
+               return SoftHSM::i()->C_DigestKey(hSession, hObject);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finalise the digest operation in the specified session and return the digest
+PKCS_API CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DigestFinal(hSession, pDigest, pulDigestLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise a signing operation using the specified key and mechanism
+PKCS_API CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignInit(hSession, pMechanism, hKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Sign the data in a single pass operation
+PKCS_API CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Sign(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running signing operation with additional data
+PKCS_API CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignUpdate(hSession, pPart, ulPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finalise a running signing operation and return the signature
+PKCS_API CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignFinal(hSession, pSignature, pulSignatureLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise a signing operation that allows recovery of the signed data
+PKCS_API CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignRecoverInit(hSession, pMechanism, hKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Perform a single part signing operation that allows recovery of the signed data
+PKCS_API CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignRecover(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise a verification operation using the specified key and mechanism
+PKCS_API CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_VerifyInit(hSession, pMechanism, hKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Perform a single pass verification operation
+PKCS_API CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_Verify(hSession, pData, ulDataLen, pSignature, ulSignatureLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running verification operation with additional data
+PKCS_API CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_VerifyUpdate(hSession, pPart, ulPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Finalise the verification operation and check the signature
+PKCS_API CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_VerifyFinal(hSession, pSignature, ulSignatureLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Initialise a verification operation the allows recovery of the signed data from the signature
+PKCS_API CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_VerifyRecoverInit(hSession, pMechanism, hKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Perform a single part verification operation and recover the signed data
+PKCS_API CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_VerifyRecover(hSession, pSignature, ulSignatureLen, pData, pulDataLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running multi-part encryption and digesting operation
+PKCS_API CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DigestEncryptUpdate(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running multi-part decryption and digesting operation
+PKCS_API CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pDecryptedPart, CK_ULONG_PTR pulDecryptedPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DecryptDigestUpdate(hSession, pPart, ulPartLen, pDecryptedPart, pulDecryptedPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running multi-part signing and encryption operation
+PKCS_API CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SignEncryptUpdate(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Update a running multi-part decryption and verification operation
+PKCS_API CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_DecryptVerifyUpdate(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Generate a secret key using the specified mechanism
+PKCS_API CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
+{
+       try
+       {
+               return SoftHSM::i()->C_GenerateKey(hSession, pMechanism, pTemplate, ulCount, phKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Generate a key-pair using the specified mechanism
+PKCS_API CK_RV C_GenerateKeyPair
+(
+       CK_SESSION_HANDLE hSession, 
+       CK_MECHANISM_PTR pMechanism, 
+       CK_ATTRIBUTE_PTR pPublicKeyTemplate, 
+       CK_ULONG ulPublicKeyAttributeCount, 
+       CK_ATTRIBUTE_PTR pPrivateKeyTemplate, 
+       CK_ULONG ulPrivateKeyAttributeCount,
+       CK_OBJECT_HANDLE_PTR phPublicKey, 
+       CK_OBJECT_HANDLE_PTR phPrivateKey
+)
+{
+       try
+       {
+               return SoftHSM::i()->C_GenerateKeyPair(hSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Wrap the specified key using the specified wrapping key and mechanism
+PKCS_API CK_RV C_WrapKey
+(
+       CK_SESSION_HANDLE hSession,
+       CK_MECHANISM_PTR pMechanism, 
+       CK_OBJECT_HANDLE hWrappingKey, 
+       CK_OBJECT_HANDLE hKey, 
+       CK_BYTE_PTR pWrappedKey, 
+       CK_ULONG_PTR pulWrappedKeyLen
+)
+{
+       try
+       {
+               return SoftHSM::i()->C_WrapKey(hSession, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Unwrap the specified key using the specified unwrapping key
+PKCS_API CK_RV C_UnwrapKey
+(
+       CK_SESSION_HANDLE hSession, 
+       CK_MECHANISM_PTR pMechanism, 
+       CK_OBJECT_HANDLE hUnwrappingKey, 
+       CK_BYTE_PTR pWrappedKey, 
+       CK_ULONG ulWrappedKeyLen,
+       CK_ATTRIBUTE_PTR pTemplate, 
+       CK_ULONG ulCount, 
+       CK_OBJECT_HANDLE_PTR phKey
+)
+{
+       try
+       {
+               return SoftHSM::i()->C_UnwrapKey(hSession, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulCount, phKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Derive a key from the specified base key
+PKCS_API CK_RV C_DeriveKey
+(
+       CK_SESSION_HANDLE hSession, 
+       CK_MECHANISM_PTR pMechanism, 
+       CK_OBJECT_HANDLE hBaseKey, 
+       CK_ATTRIBUTE_PTR pTemplate, 
+       CK_ULONG ulCount, 
+       CK_OBJECT_HANDLE_PTR phKey
+)
+{
+       try
+       {
+               return SoftHSM::i()->C_DeriveKey(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Seed the random number generator with new data
+PKCS_API CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_SeedRandom(hSession, pSeed, ulSeedLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Generate the specified amount of random data
+PKCS_API CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen)
+{
+       try
+       {
+               return SoftHSM::i()->C_GenerateRandom(hSession, pRandomData, ulRandomLen);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Legacy function
+PKCS_API CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_GetFunctionStatus(hSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Legacy function
+PKCS_API CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession)
+{
+       try
+       {
+               return SoftHSM::i()->C_CancelFunction(hSession);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
+// Wait or poll for a slot even on the specified slot
+PKCS_API CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
+{
+       try
+       {
+               return SoftHSM::i()->C_WaitForSlotEvent(flags, pSlot, pReserved);
+       }
+       catch (...)
+       {
+               FatalException();
+       }
+
+       return CKR_FUNCTION_FAILED;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/DB.cpp b/SoftHSMv2/src/lib/object_store/DB.cpp
new file mode 100644 (file)
index 0000000..d82d7cb
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DB.cpp
+
+ Specifies classes to access the Token Database
+ *****************************************************************************/
+#define HAVE_SQL_TRACE 0
+
+#include "config.h"
+#include "OSPathSep.h"
+#include "log.h"
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+#include <vector>
+#include <sqlite3.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "DB.h"
+
+#if HAVE_SQL_TRACE
+static void xTrace(void*connectionLabel,const char*zSql)
+{
+       const char *label = static_cast<const char *>(connectionLabel);
+       if (label)
+               std::cout << std::endl << label << ": " << zSql ;
+       else
+               std::cout << std::endl << zSql ;
+}
+#endif
+
+static int static_log_err(const char *format, va_list ap)
+{
+       std::vector<char> logMessage;
+       logMessage.resize(4096);
+       vsnprintf(&logMessage[0], 4096, format, ap);
+       ERROR_MSG(&logMessage[0]);
+       return 0;
+}
+
+static DB::LogErrorHandler static_LogErrorhandler = static_log_err;
+
+void DB::logError(const std::string &format, ...)
+{
+       if (!static_LogErrorhandler)
+               return;
+       va_list args;
+       va_start(args, format);
+       static_LogErrorhandler(format.c_str(),args);
+       va_end(args);
+}
+
+DB::LogErrorHandler DB::setLogErrorHandler(DB::LogErrorHandler handler)
+{
+       LogErrorHandler temp = static_LogErrorhandler;
+       static_LogErrorhandler = handler;
+       return temp;
+}
+
+void DB::resetLogErrorHandler()
+{
+       static_LogErrorhandler = static_log_err;
+}
+
+static void reportErrorDB(sqlite3 *db)
+{
+       if (!db) {
+               DB::logError("sqlite3 pointer is NULL");
+               return;
+       }
+
+       int rv = sqlite3_errcode(db);
+       if (rv == SQLITE_OK || rv == SQLITE_ROW || rv == SQLITE_DONE)
+               return;
+
+#ifdef HAVE_SILENT_BUSY_AND_LOCKED_ERRORS
+       // Either the database file is locked (SQLITE_BUSY)
+       // or a table in the database is locked (SQLITE_LOCKED)
+       if (rv == SQLITE_BUSY || rv == SQLITE_LOCKED)
+               return;
+#endif
+
+       DB::logError("SQLITE3: %s (%d)", sqlite3_errmsg(db), rv);
+}
+
+static void reportError(sqlite3_stmt *stmt)
+{
+       if (!stmt) {
+               DB::logError("sqlite3_stmt pointer is NULL");
+               return;
+       }
+       reportErrorDB(sqlite3_db_handle(stmt));
+}
+
+static time_t sqlite3_gmtime(struct tm *tm)
+{
+       // We don't want to depend on timegm() so we use a workaround via the
+       // gmtime_r() function to determine this.
+       // As input we use a moment in time just 10 days after the POSIX epoch.
+       // The POSIX epoch is defined as the moment in time at midnight Coordinated
+       // Universal Time (UTC) of Thursday, January 1, 1970. A time_t value is
+       // the number of seconds elapsed since epoch.
+       struct tm ref_tm = {0,0,0,0,0,0,0,0,0,0,0};
+       ref_tm.tm_year = 70; // Years since 1900;
+       ref_tm.tm_mday = 10; // 10th
+
+       // We need the time difference between local time and UTC time.
+       // mktime will interpret the UTC time stored in tm as local time
+       // so let's assume we are in a time zone 1 hour ahead of UTC (UTC+1)
+       // then a time of 13:00 interpreted as local time needs 1 hour subtracted
+       // to arrive at UTC time. This UTC time is then converted to a POSIX
+       // time_t value.
+       time_t posix_time = mktime(&ref_tm);
+
+       // Use gmtime_r to convert the POSIX time back to a tm struct.
+       // No time adjustment is done this time because POSIX time is
+       // defined in terms of UTC.
+       gmtime_r(&posix_time, &ref_tm);
+       if (ref_tm.tm_isdst != 0) {
+               DB::logError("expected gmtime_r to return zero in tm_isdst member of tm struct");
+               return ((time_t)-1);
+       }
+
+       // Using mktime again to convert tm. This will again subtract 1 hour from
+       // the time (under the assumption that we are 1 hour ahead of UTC).
+       // We can now use this to determine how much local time differred
+       // from UTC time on january the 10th 1970
+       long diff_time = posix_time - mktime(&ref_tm);
+
+       // We explicitly set tm_isdst to zero to prevent errors
+       // when the time we are trying to convert is occuring at
+       // the moment when a dst change is in progress.
+       // We require mktime to respect our setting of tm_isdst
+       // indicating that no dst is in effect.
+       tm->tm_isdst = 0; // Tell (and force) mktime not to take dst into account.
+
+       // We now can calculate and return a correct POSIX time.
+       // So, although mktime() interprets gm_tm as local time adjusts for
+       // the time difference between local time and UTC time. We then undo
+       // that adjustment by adding diff_time.
+       return mktime(tm) + diff_time;
+}
+
+/**************************
+ * Handle
+ **************************/
+
+class DB::Handle {
+public:
+       int _refcount;
+       sqlite3_stmt *_stmt;
+       Handle(sqlite3_stmt *stmt)
+               : _refcount(1), _stmt(stmt)
+       {
+       }
+       ~Handle()
+       {
+               if (_stmt)
+               {
+                       sqlite3_finalize(_stmt);
+                       _stmt = NULL;
+               }
+       }
+
+       Handle *retain()
+       {
+               if (_refcount)
+               {
+                       _refcount++;
+                       return this;
+               }
+               return NULL;
+       }
+       void release()
+       {
+               if (_refcount)
+               {
+                       _refcount--;
+                       if (_refcount)
+                               return;
+                       delete this;
+               }
+       }
+       bool reset()
+       {
+               if (sqlite3_reset(_stmt) != SQLITE_OK)
+               {
+                       reportError(_stmt);
+                       return false;
+               }
+               return true;
+       }
+       Statement::ReturnCode step()
+       {
+               int rv = sqlite3_step(_stmt);
+               if (rv != SQLITE_ROW && rv != SQLITE_DONE)
+               {
+                       reportError(_stmt);
+                       return Statement::ReturnCodeError;
+               }
+
+               if (rv==SQLITE_ROW)
+               {
+                       return Statement::ReturnCodeRow;
+               }
+
+               return Statement::ReturnCodeDone;
+       }
+private:
+       // disable evil constructors
+       Handle(const Handle &);
+       Handle & operator=(const Handle &);
+};
+
+DB::Statement::Statement()
+       : _handle(NULL)
+{
+}
+
+DB::Statement::Statement(sqlite3_stmt *statement)
+       : _handle(new Handle(statement))
+{
+}
+
+DB::Statement::Statement(const DB::Statement &statement)
+       : _handle(statement._handle)
+{
+       if (_handle)
+               _handle = _handle->retain();
+}
+
+DB::Statement &DB::Statement::operator=(const DB::Statement &statement)
+{
+       if (this != &statement)
+       {
+               Handle *tmp = NULL;
+               if (statement._handle) {
+                       tmp = statement._handle->retain();
+               }
+               if (_handle) {
+                       _handle->release();
+               }
+               _handle = tmp;
+       }
+       return *this;
+}
+
+DB::Statement::~Statement()
+{
+       if (_handle) {
+               _handle->release();
+               _handle = NULL;
+       }
+}
+
+bool DB::Statement::isValid()
+{
+       return _handle != NULL && _handle->_stmt != NULL;
+}
+
+int DB::Statement::refcount()
+{
+       return _handle ? _handle->_refcount : 0;
+}
+
+
+bool DB::Statement::reset()
+{
+       if (!isValid()) {
+               DB::logError("Statement::reset: statement is not valid");
+               return false;
+       }
+       return _handle->reset();
+}
+
+DB::Statement::ReturnCode DB::Statement::step()
+{
+       if (!isValid()) {
+               DB::logError("Statement::step: statement is not valid");
+               return ReturnCodeError;
+       }
+       return _handle->step();
+}
+
+DB::Handle *DB::Statement::handle() const
+{
+       return _handle;
+}
+
+/**************************
+ * Bindings
+ **************************/
+
+DB::Bindings::Bindings()
+       : Statement()
+{
+}
+
+DB::Bindings::Bindings(const Statement &statement)
+       : Statement(statement)
+{
+}
+
+bool DB::Bindings::clear()
+{
+       if (!isValid()) {
+               DB::logError("Bindings::clear: statement is not valid");
+               return false;
+       }
+       if (sqlite3_clear_bindings(_handle->_stmt) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+bool DB::Bindings::bindBlob(int index, const void *value, int n, void(*destruct)(void*))
+{
+       if (!isValid()) {
+               DB::logError("Bindings::bindBlob: statement is not valid");
+               return false;
+       }
+       if (sqlite3_bind_blob(_handle->_stmt, index, value, n, destruct) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+bool DB::Bindings::bindDouble(int index, double value)
+{
+       if (!isValid()) {
+               DB::logError("Bindings::bindDouble: statement is not valid");
+               return false;
+       }
+       if (sqlite3_bind_double(_handle->_stmt, index, value) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+bool DB::Bindings::bindInt(int index, int value)
+{
+       if (!isValid()) {
+               DB::logError("Bindings::bindInt: statement is not valid");
+               return false;
+       }
+       if (sqlite3_bind_int(_handle->_stmt, index, value) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+bool DB::Bindings::bindInt64(int index, long long value)
+{
+       if (!isValid()) {
+               DB::logError("Bindings::bindInt64: statement is not valid");
+               return false;
+       }
+       if (sqlite3_bind_int64(_handle->_stmt, index, value) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+//bool DB::Bindings::bindNull(int index)
+//{
+//#if 0
+//     int sqlite3_bind_null(sqlite3_stmt*, int);
+//#endif
+//     return false;
+//}
+
+bool DB::Bindings::bindText(int index, const char *value, int n, void (*destruct)(void *))
+{
+       if (!isValid()) {
+               DB::logError("Bindings::bindText: statement is not valid");
+               return false;
+       }
+       if (sqlite3_bind_text(_handle->_stmt, index, value, n, destruct) != SQLITE_OK) {
+               reportError(_handle->_stmt);
+               return false;
+       }
+       return true;
+}
+
+//bool DB::Bindings::bindZeroBlob(int index, int n)
+//{
+//#if 0
+//     int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+//#endif
+//     return false;
+//}
+
+/**************************
+ * Result
+ **************************/
+
+DB::Result::Result()
+       : Statement()
+{
+}
+
+DB::Result::Result(const Statement &statement)
+       : Statement(statement)
+{
+}
+
+#if 0
+unsigned int DB::Result::getField(const std::string &fieldname)
+{
+       unsigned int fieldidx = fields[fieldname];
+       if (fieldidx == 0)
+               DB::logError("Result: invalid field name \"%s\"",fieldname.c_str());
+       return fieldidx;
+}
+#endif
+
+bool DB::Result::fieldIsNull(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::fieldIsNull: statement is not valid");
+               return true;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return true;
+       }
+       int column_type = sqlite3_column_type(_handle->_stmt, fieldidx-1);
+       return column_type == SQLITE_NULL;
+}
+
+time_t DB::Result::getDatetime(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getDatetime: statement is not valid");
+               return ((time_t)-1);
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return ((time_t)-1);
+       }
+
+       const unsigned char *value = sqlite3_column_text(_handle->_stmt, fieldidx-1);
+       int valuelen = sqlite3_column_bytes(_handle->_stmt, fieldidx-1);
+
+       unsigned long years,mons,days,hours,mins,secs;
+       struct tm gm_tm = {0,0,0,0,0,0,0,0,0,0,0};
+       gm_tm.tm_isdst = 0; // Tell mktime not to take dst into account.
+       gm_tm.tm_year = 70; // 1970
+       gm_tm.tm_mday = 1; // 1th day of the month
+       const char *p = (const char *)value;
+       char *pnext;
+       bool bdateonly = true;
+       switch (valuelen) {
+               case 19:        // 2011-12-31 23:59:59
+                       bdateonly = false;
+                       // falls through to next case
+               case 10:        // 2011-12-31
+                       years = strtoul(p,&pnext,10);
+                       gm_tm.tm_year = ((int)years)-1900; /* years since 1900 */
+                       p = pnext+1;
+                       mons = strtoul(p,&pnext,10);
+                       gm_tm.tm_mon = ((int)mons)-1; /* months since January [0-11] */
+                       p = pnext+1;
+                       days = strtoul(p,&pnext,10);
+                       gm_tm.tm_mday = ((int)days); /* day of the month [1-31] */
+                       p = pnext+1;
+                       if (bdateonly)
+                               break;
+                       // falls through to next case
+               case 8:         // 23:59:59
+                       hours = strtoul(p,&pnext,10);
+                       gm_tm.tm_hour = (int)hours; /* hours since midnight [0-23] */
+                       if ((pnext-p) != 2) {
+                               DB::logError("Result: invalid hours in time: '%s'",value);
+                               return 0;
+                       }
+                       p = pnext+1;
+                       mins = strtoul(p,&pnext,10);
+                       gm_tm.tm_min = (int)mins; /* minutes after the hour [0-59] */
+                       if ((pnext-p) != 2) {
+                               DB::logError("Result: invalid minutes in time: '%s'",value);
+                               return 0;
+                       }
+                       p = pnext+1;
+                       secs = strtoul(p,&pnext,10);
+                       gm_tm.tm_sec = (int)secs; /* seconds after the minute [0-60] */
+                       if ((pnext-p) != 2) {
+                               DB::logError("Result: invalid seconds in time: '%s'",value);
+                               return 0;
+                       }
+                       break;
+               default:
+                       DB::logError("Result: invalid date/time value: '%s'",value);
+                       return 0;
+       }
+
+       return sqlite3_gmtime(&gm_tm);
+}
+
+unsigned char DB::Result::getUChar(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getUChar: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       int value = sqlite3_column_int(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return (unsigned char)value;
+}
+
+float DB::Result::getFloat(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getFloat: statement is not valid");
+               return 0.0f;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0.0f;
+       }
+       double value = sqlite3_column_double(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return (float)value;
+}
+
+double DB::Result::getDouble(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getDouble: statement is not valid");
+               return 0.0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0.0;
+       }
+       double value = sqlite3_column_double(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return value;
+}
+
+int DB::Result::getInt(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getInt: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       int value = sqlite3_column_int(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return value;
+}
+
+unsigned int DB::Result::getUInt(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getUInt: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       int value = sqlite3_column_int(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return (unsigned int)value;
+}
+
+long long DB::Result::getLongLong(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getLongLong: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       sqlite3_int64 value = sqlite3_column_int64(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return value;
+}
+
+unsigned long long DB::Result::getULongLong(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getULongLong: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       sqlite3_int64 value = sqlite3_column_int64(_handle->_stmt, fieldidx-1);
+       reportError(_handle->_stmt);
+       return (unsigned long long)value;
+}
+
+const char *DB::Result::getString(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getString: statement is not valid");
+               return NULL;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return NULL;
+       }
+       const unsigned char *value = sqlite3_column_text(_handle->_stmt,fieldidx-1);
+       reportError(_handle->_stmt);
+       return (const char *)value;
+}
+
+const unsigned char *DB::Result::getBinary(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getBinary: statement is not valid");
+               return NULL;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return NULL;
+       }
+       const unsigned char *value =
+               (const unsigned char *)sqlite3_column_blob(_handle->_stmt,fieldidx-1);
+       reportError(_handle->_stmt);
+       return value;
+}
+
+size_t DB::Result::getFieldLength(unsigned int fieldidx)
+{
+       if (!isValid()) {
+               DB::logError("Result::getFieldLength: statement is not valid");
+               return 0;
+       }
+       if (fieldidx == 0) {
+               DB::logError("Result: zero is an invalid field index");
+               return 0;
+       }
+       int value = sqlite3_column_bytes(_handle->_stmt,fieldidx-1);
+       reportError(_handle->_stmt);
+       return (size_t)value;
+}
+
+bool DB::Result::firstRow()
+{
+       if (!isValid()) {
+               DB::logError("Result::firstRow: statement is not valid");
+               return false;
+       }
+       return _handle->reset() && _handle->step()==Statement::ReturnCodeRow;
+}
+
+bool DB::Result::nextRow()
+{
+       if (!isValid()) {
+               DB::logError("Result::nextRow: statement is not valid");
+               return false;
+       }
+       return _handle->step()==Statement::ReturnCodeRow;
+}
+
+/**************************
+ * Connection
+ **************************/
+
+DB::Connection *DB::Connection::Create(const std::string &dbdir, const std::string &dbname)
+{
+       if (dbdir.length() == 0) {
+               DB::logError("Connection::Create: database directory parameter dbdir is empty");
+               return NULL;
+       }
+
+       if (dbname.length() == 0) {
+               DB::logError("Connection::Create: database name parameter dbname is empty");
+               return NULL;
+       }
+
+       return new Connection(dbdir,dbname);
+}
+
+DB::Connection::Connection(const std::string &dbdir, const std::string &dbname)
+       : _dbdir(dbdir)
+       , _dbpath(dbdir + OS_PATHSEP + dbname)
+       , _db(NULL)
+{
+}
+
+DB::Connection::~Connection()
+{
+       close();
+}
+
+const std::string &DB::Connection::dbdir()
+{
+       return _dbdir;
+}
+
+const std::string &DB::Connection::dbpath()
+{
+       return _dbpath;
+}
+
+DB::Statement DB::Connection::prepare(const std::string &format, ...){
+       // pstatement will hold a dynamically allocated string that needs to be deleted.
+       char *pstatement = NULL;
+
+       // short form
+       char statement[128];
+       va_list args;
+       va_start(args, format);
+       int cneeded = vsnprintf(statement,sizeof(statement),format.c_str(),args);
+       va_end(args);
+       if (cneeded<0) {
+               DB::logError("Connection::prepare: vsnprintf encoding error");
+               return Statement();
+       }
+       if (((size_t)cneeded)>=sizeof(statement)) {
+               // long form
+               pstatement = new char[cneeded+1];
+               if (!pstatement) {
+                       DB::logError("Connection::prepare: out of memory");
+                       return Statement();
+               }
+               va_start(args, format);
+               bool ok = vsnprintf(pstatement,cneeded+1,format.c_str(),args)==cneeded;
+               va_end(args);
+               if (!ok) {
+                       DB::logError("Connection::prepare: vsnprintf error");
+                       delete[] pstatement;
+                       return  Statement();
+               }
+       }
+
+       sqlite3_stmt *stmt = NULL;
+       int rv = sqlite3_prepare_v2(_db,
+                                                               pstatement ? pstatement : statement,
+                                                               cneeded+1,
+                                                               &stmt,
+                                                               NULL);
+
+       if (pstatement)
+               delete[] pstatement;
+
+       if (rv != SQLITE_OK) {
+               reportErrorDB(_db);
+               if (stmt)
+                       sqlite3_finalize(stmt);
+               return Statement();
+       }
+
+       if (!stmt) {
+               DB::logError("Connection::prepare: expected sqlite3_prepare_v2 to return a compiled "
+                                       "statement, got NULL, out of memory ?");
+               return Statement();
+       }
+
+       return Statement(stmt);
+}
+
+DB::Result DB::Connection::perform(DB::Statement &statement)
+{
+       return (statement.step()==Statement::ReturnCodeRow) ?  Result(statement) : Result();
+}
+
+bool DB::Connection::execute(DB::Statement &statement)
+{
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
+bool DB::Connection::connect(const char *
+#if HAVE_SQL_TRACE
+                                                        connectionLabel
+#endif
+                                                        )
+{
+       // Create and set file permissions if the DB does not exist.
+       int fd = open(_dbpath.c_str(), O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd == -1)
+       {
+               DB::logError("Could not open database: %s (errno %i)",
+                            _dbpath.c_str(), errno);
+               return false;
+       }
+       ::close(fd);
+
+       int rv = sqlite3_open_v2(_dbpath.c_str(),
+                                                        &_db,
+                                                        SQLITE_OPEN_READWRITE
+                                                        | SQLITE_OPEN_CREATE
+                                                        | SQLITE_OPEN_FULLMUTEX,
+                                                        NULL);
+
+       if (rv != SQLITE_OK) {
+               reportErrorDB(_db);
+               return false;
+       }
+
+       int foreignKeyEnabled = 0;
+       rv = sqlite3_db_config(_db,SQLITE_DBCONFIG_ENABLE_FKEY,1,&foreignKeyEnabled);
+       if (rv != SQLITE_OK) {
+               reportErrorDB(_db);
+               return false;
+       }
+
+       if (foreignKeyEnabled != 1) {
+               DB::logError("Connection::connect: foreign key support not enabled");
+               return false;
+       }
+
+       rv = sqlite3_busy_timeout(_db, 15000); // 15 seconds
+       if (rv != SQLITE_OK) {
+               reportErrorDB(_db);
+               return false;
+       }
+#if HAVE_SQL_TRACE
+       sqlite3_trace(_db, xTrace, const_cast<char *>(connectionLabel));
+#endif
+       return true;
+}
+
+void DB::Connection::close()
+{
+       if (_db) {
+               sqlite3_close(_db);
+               _db = NULL;
+       }
+}
+
+bool DB::Connection::setBusyTimeout(int ms)
+{
+       int rv = sqlite3_busy_timeout(_db, ms);
+       if (rv != SQLITE_OK) {
+               reportErrorDB(_db);
+               return false;
+       }
+
+       return true;
+}
+
+bool DB::Connection::tableExists(const std::string &tablename)
+{
+       Statement statement = prepare("select name from sqlite_master where type='table' and name='%s';",tablename.c_str());
+       return statement.step()==Statement::ReturnCodeRow && statement.step()==Statement::ReturnCodeDone;
+}
+
+long long DB::Connection::lastInsertRowId()
+{
+       return sqlite3_last_insert_rowid(_db);
+}
+
+bool DB::Connection::inTransaction()
+{
+       return sqlite3_get_autocommit(_db)==0;
+}
+
+bool DB::Connection::beginTransactionRO()
+{
+       Statement statement = prepare("begin");
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
+bool DB::Connection::endTransactionRO()
+{
+       Statement statement = prepare("end");
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
+bool DB::Connection::beginTransactionRW()
+{
+       Statement statement = prepare("begin immediate");
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
+bool DB::Connection::commitTransaction()
+{
+       Statement statement = prepare("commit");
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
+bool DB::Connection::rollbackTransaction()
+{
+       Statement statement = prepare("rollback");
+       return statement.step()==Statement::ReturnCodeDone;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/DB.h b/SoftHSMv2/src/lib/object_store/DB.h
new file mode 100644 (file)
index 0000000..e4e1a11
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DB.h
+
+ Specifies classes to access the Token Database
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DB_H
+#define _SOFTHSM_V2_DB_H
+
+#include "config.h"
+
+#include <string>
+#include <sqlite3.h>
+
+namespace DB {
+
+// Log an error to the error handler that has been setup using a call to setLogErrorHandler declared below.
+void logError(const std::string &format, ...);
+
+// The ap parameter has already been started with va_start.
+// So the handler only has to pass this on to a vprintf function
+// to actually print it.
+typedef int (*LogErrorHandler)(const char *format, va_list ap);
+
+// Set an alternative for vprintf to log the actual errors.
+// Set to NULL to disable logging al together.
+LogErrorHandler setLogErrorHandler(LogErrorHandler handler);
+
+// Set the log error handler back to the default value that logs to stdout.
+void resetLogErrorHandler();
+
+// Forward declaration of the handle class used by Statement, Binding and Result.
+class Handle;
+
+// Responsible for holding on to a prepared statement.
+// After a prepared statement has been used it can be reused when the same query is performed again.
+class Statement {
+public:
+       Statement();
+       Statement(sqlite3_stmt *statement);
+       Statement(const Statement &statement);
+       Statement &operator=(const Statement &statement);
+
+       virtual ~Statement();
+       bool isValid();
+
+       // Something we'd like to check during testing.
+       int refcount();
+
+       // Reset a prepared statement
+       bool reset();
+
+       // Perform a single step of the prepared statement.
+       enum ReturnCode {
+               ReturnCodeRow,
+               ReturnCodeDone,
+               ReturnCodeError
+       };
+
+       ReturnCode step();
+
+       Handle *handle() const;
+protected:
+       Handle *_handle;
+};
+
+// Responsible for allowing parameters to be bound to statements.
+// On a statement that has been performed or executed you first
+// need to call reset() before new parameters can be bound.
+class Bindings : public Statement {
+public:
+       Bindings();
+       Bindings(const Statement &statement);
+
+       // To clear all existing bindings call this method.
+       bool clear();
+
+       // Bind a value to a parameter in a prepared statement
+       bool bindBlob(int index, const void *value, int n, void(*destruct)(void*));
+       bool bindDouble(int index, double value);
+       bool bindInt(int index, int value);
+       bool bindInt64(int index, long long value );
+       //bool bindNull(int index);
+       bool bindText(int index, const char *value, int n, void(*destruct)(void*));
+       //bool bindZeroBlob(int index, int n);
+};
+
+// Responsible for providing access to the result set of a query.
+// Used for queries that actually provide a result set.
+// A result that is returned will be positioned at the first row.
+class Result : public Statement {
+public:
+       Result();
+       Result(const Statement &statement);
+
+       bool fieldIsNull(unsigned int fieldidx);
+       time_t getDatetime(unsigned int fieldidx);
+       unsigned char getUChar(unsigned int fieldidx);
+       float getFloat(unsigned int fieldidx);
+       double getDouble(unsigned int fieldidx);
+       int getInt(unsigned int fieldidx);
+       unsigned int getUInt(unsigned int fieldidx);
+       long long getLongLong(unsigned int fieldidx);
+       unsigned long long getULongLong(unsigned int fieldidx);
+
+       const char *getString(unsigned int fieldidx);
+       const unsigned char *getBinary(unsigned int fieldidx);
+       size_t getFieldLength(unsigned int fieldidx);
+
+       // Position the result on the first row again.
+       bool firstRow();
+
+       // Position the result on the next row.
+       bool nextRow();
+};
+
+// Responsible for connection to the database and for managing prepared statements.
+class Connection {
+public:
+       static Connection *Create(const std::string &dbdir, const std::string &dbname);
+       virtual ~Connection();
+
+       // value that was passed into dbdir when this connection was created.
+       const std::string &dbdir();
+
+       // concatenation of dbdir and dbname
+       const std::string &dbpath();
+
+       Statement prepare(const std::string &format, ...);
+       Result perform(Statement &statement);
+       bool execute(Statement &statement);
+
+       bool connect(const char *connectionLabel = NULL);
+       void close();
+
+       bool tableExists(const std::string &tablename);
+       long long lastInsertRowId();
+
+       bool inTransaction();
+       bool beginTransactionRO();
+       bool endTransactionRO();
+       bool beginTransactionRW();
+       bool commitTransaction();
+       bool rollbackTransaction();
+
+       // Set the busy timeout that the database layer will wait for a database lock to become available.
+       bool setBusyTimeout(int ms);
+private:
+       std::string _dbdir;
+       std::string _dbpath;
+       sqlite3 *_db;
+
+       Connection(const std::string &dbdir, const std::string &dbname);
+
+       // disable evil constructors
+       Connection(const Connection &);
+       void operator=(const Connection&);
+};
+
+}
+
+#endif // !_SOFTHSM_V2_DB_H
diff --git a/SoftHSMv2/src/lib/object_store/DBObject.cpp b/SoftHSMv2/src/lib/object_store/DBObject.cpp
new file mode 100644 (file)
index 0000000..d2515bd
--- /dev/null
@@ -0,0 +1,1493 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObject.h
+
+ This class represents object records in a database
+ *****************************************************************************/
+
+#include "config.h"
+#include "DBObject.h"
+#include "OSPathSep.h"
+#include "DB.h"
+#include "OSAttributes.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cstdio>
+#include <map>
+
+// Create an object that can access a record, but don't do anything yet.
+DBObject::DBObject(DB::Connection *connection, ObjectStoreToken *token)
+       : _mutex(MutexFactory::i()->getMutex()), _connection(connection), _token(token), _objectId(0), _transaction(NULL)
+{
+
+}
+
+DBObject::DBObject(DB::Connection *connection, ObjectStoreToken *token, long long objectId)
+       : _mutex(MutexFactory::i()->getMutex()), _connection(connection), _token(token), _objectId(objectId), _transaction(NULL)
+{
+}
+
+// Destructor
+DBObject::~DBObject()
+{
+       for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _attributes.begin(); it!=_attributes.end(); ++it) {
+               delete it->second;
+               it->second = NULL;
+       }
+       if (_transaction)
+       {
+               for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
+                       delete it->second;
+                       it->second = NULL;
+               }
+               delete _transaction;
+       }
+       MutexFactory::i()->recycleMutex(_mutex);
+}
+
+void DBObject::dropConnection()
+{
+       MutexLocker lock(_mutex);
+
+       _connection = NULL;
+}
+
+// create tables to support storage of attributes for the DBObject
+bool DBObject::createTables()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       // Create the tables inside the database
+       DB::Statement cr_object = _connection->prepare("create table object (id integer primary key autoincrement);");
+       if (!_connection->execute(cr_object))
+       {
+               ERROR_MSG("Failed to create \"object\" table");
+               return false;
+       }
+
+       // attribute_text
+       DB::Statement cr_attr_text = _connection->prepare(
+               "create table attribute_text ("
+               "value text,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_text))
+       {
+               ERROR_MSG("Failed to create \"attribute_text\" table");
+               return false;
+       }
+
+       // attribute_integer
+       DB::Statement cr_attr_integer = _connection->prepare(
+               "create table attribute_integer ("
+               "value integer,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_integer))
+       {
+               ERROR_MSG("Failed to create \"attribute_integer\" table");
+               return false;
+       }
+
+       // attribute_binary
+       DB::Statement cr_attr_binary = _connection->prepare(
+               "create table attribute_binary ("
+               "value blob,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_binary))
+       {
+               ERROR_MSG("Failed to create \"attribute_binary\" table");
+               return false;
+       }
+
+       // attribute_array
+       DB::Statement cr_attr_array = _connection->prepare(
+               "create table attribute_array ("
+               "value blob,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_array))
+       {
+               ERROR_MSG("Failed to create \"attribute_array\" table");
+               return false;
+       }
+
+       // attribute_boolean
+       DB::Statement cr_attr_boolean = _connection->prepare(
+               "create table attribute_boolean ("
+               "value boolean,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_boolean))
+       {
+               ERROR_MSG("Failed to create \"attribute_boolean\" table");
+               return false;
+       }
+
+       // attribute_datetime
+       DB::Statement cr_attr_datetime = _connection->prepare(
+               "create table attribute_datetime ("
+               "value datetime,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_datetime))
+       {
+               ERROR_MSG("Failed to create \"attribute_datetime\" table");
+               return false;
+       }
+
+       // attribute_real
+       DB::Statement cr_attr_real = _connection->prepare(
+               "create table attribute_real ("
+               "value real,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       if (!_connection->execute(cr_attr_real))
+       {
+               ERROR_MSG("Failed to create \"attribute_real\" table");
+               return false;
+       }
+
+       return true;
+}
+
+bool DBObject::dropTables()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       // Create the tables inside the database
+       DB::Statement dr_object = _connection->prepare("drop table object");
+       if (!_connection->execute(dr_object))
+       {
+               ERROR_MSG("Failed to drop \"object\" table");
+               return false;
+       }
+
+       // attribute_text
+       DB::Statement dr_attr_text = _connection->prepare("drop table attribute_text");
+       if (!_connection->execute(dr_attr_text))
+       {
+               ERROR_MSG("Failed to drop \"attribute_text\" table");
+               return false;
+       }
+
+       // attribute_integer
+       DB::Statement dr_attr_integer = _connection->prepare("drop table attribute_integer");
+       if (!_connection->execute(dr_attr_integer))
+       {
+               ERROR_MSG("Failed to drop \"attribute_integer\" table");
+               return false;
+       }
+
+       // attribute_binary
+       DB::Statement dr_attr_binary = _connection->prepare("drop table attribute_binary");
+       if (!_connection->execute(dr_attr_binary))
+       {
+               ERROR_MSG("Failed to drop \"attribute_binary\" table");
+               return false;
+       }
+
+       // attribute_array
+       DB::Statement dr_attr_array = _connection->prepare("drop table attribute_array");
+       if (!_connection->execute(dr_attr_array))
+       {
+               ERROR_MSG("Failed to drop \"attribute_array\" table");
+               return false;
+       }
+
+       // attribute_boolean
+       DB::Statement dr_attr_boolean = _connection->prepare("drop table attribute_boolean");
+       if (!_connection->execute(dr_attr_boolean))
+       {
+               ERROR_MSG("Failed to drop \"attribute_boolean\" table");
+               return false;
+       }
+
+       // attribute_datetime
+       DB::Statement dr_attr_datetime = _connection->prepare("drop table attribute_datetime");
+       if (!_connection->execute(dr_attr_datetime))
+       {
+               ERROR_MSG("Failed to drop \"attribute_datetime\" table");
+               return false;
+       }
+
+       // attribute_real
+       DB::Statement dr_attr_real = _connection->prepare("drop table attribute_real");
+       if (!_connection->execute(dr_attr_real))
+       {
+               ERROR_MSG("Failed to drop \"attribute_real\" table");
+               return false;
+       }
+
+       return true;
+}
+
+bool DBObject::find(long long objectId)
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       if (objectId == 0) {
+               ERROR_MSG("Invalid object_id 0 passed to find");
+               return false;
+       }
+
+       // find the object in the database for the given object_id
+       DB::Statement statement = _connection->prepare(
+                               "select id from object where id=%lld",
+                               objectId);
+       if (!statement.isValid()) {
+               ERROR_MSG("Preparing object selection statement failed");
+               return false;
+       }
+
+       DB::Result result = _connection->perform(statement);
+       if (result.getLongLong(1) != objectId) {
+               ERROR_MSG("Failed to find object with id %lld",objectId);
+               return false;
+       }
+
+       _objectId = objectId;
+       return true;
+}
+
+bool DBObject::insert()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       DB::Statement statement = _connection->prepare("insert into object default values");
+
+       if (!_connection->execute(statement)) {
+               ERROR_MSG("Failed to insert a new object");
+               return false;
+       }
+
+       _objectId = _connection->lastInsertRowId();
+       return _objectId != 0;
+}
+
+bool DBObject::remove()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       DB::Statement statement = _connection->prepare("delete from object where id=%lld",_objectId);
+
+       if (!_connection->execute(statement)) {
+               ERROR_MSG("Failed to remove an existing object");
+               return false;
+       }
+
+       _objectId = 0;
+       return true;
+}
+
+long long DBObject::objectId()
+{
+       MutexLocker lock(_mutex);
+
+       return _objectId;
+}
+
+static bool isModifiable(CK_ATTRIBUTE_TYPE type)
+{
+       switch (type) {
+       case CKA_LABEL:
+       case CKA_TRUSTED:
+       case CKA_ID:
+       case CKA_ISSUER:
+       case CKA_SERIAL_NUMBER:
+       case CKA_START_DATE:
+       case CKA_END_DATE:
+       case CKA_DERIVE:
+       case CKA_SUBJECT:
+       case CKA_ENCRYPT:
+       case CKA_VERIFY:
+       case CKA_VERIFY_RECOVER:
+       case CKA_WRAP:
+       case CKA_SENSITIVE:
+       case CKA_DECRYPT:
+       case CKA_SIGN:
+       case CKA_SIGN_RECOVER:
+       case CKA_UNWRAP:
+       case CKA_EXTRACTABLE:
+       case CKA_OS_TOKENFLAGS:
+       case CKA_OS_SOPIN:
+       case CKA_OS_USERPIN:
+               return true;
+       default:
+               return false;
+       }
+}
+
+enum AttributeKind {
+       akUnknown,
+       akBoolean,
+       akInteger,
+       akBinary,
+       akAttrMap,
+       akMechSet
+};
+
+static AttributeKind attributeKind(CK_ATTRIBUTE_TYPE type)
+{
+       switch (type) {
+       case CKA_CLASS: return akInteger;
+       case CKA_TOKEN: return akBoolean;
+       case CKA_PRIVATE: return akBoolean;
+       case CKA_LABEL: return akBinary;
+       case CKA_APPLICATION: return akBinary;
+       case CKA_VALUE: return akBinary;
+       case CKA_OBJECT_ID: return akBinary;
+       case CKA_CERTIFICATE_TYPE: return akInteger;
+       case CKA_ISSUER: return akBinary;
+       case CKA_SERIAL_NUMBER: return akBinary;
+       case CKA_AC_ISSUER: return akBinary;
+       case CKA_OWNER: return akBinary;
+       case CKA_ATTR_TYPES: return akBinary;
+       case CKA_TRUSTED: return akBoolean;
+       case CKA_CERTIFICATE_CATEGORY: return akInteger;
+       case CKA_JAVA_MIDP_SECURITY_DOMAIN: return akInteger;
+       case CKA_URL: return akBinary;
+       case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: return akBinary;
+       case CKA_HASH_OF_ISSUER_PUBLIC_KEY: return akBinary;
+       case CKA_NAME_HASH_ALGORITHM: return akInteger;
+       case CKA_CHECK_VALUE: return akBinary;
+       case CKA_KEY_TYPE: return akInteger;
+       case CKA_SUBJECT: return akBinary;
+       case CKA_ID: return akBinary;
+       case CKA_SENSITIVE: return akBoolean;
+       case CKA_ENCRYPT: return akBoolean;
+       case CKA_DECRYPT: return akBoolean;
+       case CKA_WRAP: return akBoolean;
+       case CKA_UNWRAP: return akBoolean;
+       case CKA_SIGN: return akBoolean;
+       case CKA_SIGN_RECOVER: return akBoolean;
+       case CKA_VERIFY: return akBoolean;
+       case CKA_VERIFY_RECOVER: return akBoolean;
+       case CKA_DERIVE: return akBoolean;
+       case CKA_START_DATE: return akBinary;
+       case CKA_END_DATE: return akBinary;
+       case CKA_MODULUS: return akBinary;
+       case CKA_MODULUS_BITS: return akInteger;
+       case CKA_PUBLIC_EXPONENT: return akBinary;
+       case CKA_PRIVATE_EXPONENT: return akBinary;
+       case CKA_PRIME_1: return akBinary;
+       case CKA_PRIME_2: return akBinary;
+       case CKA_EXPONENT_1: return akBinary;
+       case CKA_EXPONENT_2: return akBinary;
+       case CKA_COEFFICIENT: return akBinary;
+       case CKA_PRIME: return akBinary;
+       case CKA_SUBPRIME: return akBinary;
+       case CKA_BASE: return akBinary;
+       case CKA_PRIME_BITS: return akInteger;
+       case CKA_SUBPRIME_BITS: return akInteger;
+       case CKA_VALUE_BITS: return akInteger;
+       case CKA_VALUE_LEN: return akInteger;
+       case CKA_EXTRACTABLE: return akBoolean;
+       case CKA_LOCAL: return akBoolean;
+       case CKA_NEVER_EXTRACTABLE: return akBoolean;
+       case CKA_ALWAYS_SENSITIVE: return akBoolean;
+       case CKA_KEY_GEN_MECHANISM: return akInteger;
+       case CKA_MODIFIABLE: return akBoolean;
+       case CKA_COPYABLE: return akBoolean;
+       case CKA_ECDSA_PARAMS: return akBinary;
+       case CKA_EC_POINT: return akBinary;
+       case CKA_SECONDARY_AUTH: return akBoolean;
+       case CKA_AUTH_PIN_FLAGS: return akInteger;
+       case CKA_ALWAYS_AUTHENTICATE: return akBoolean;
+       case CKA_WRAP_WITH_TRUSTED: return akBoolean;
+/*
+       case CKA_OTP_FORMAT:
+       case CKA_OTP_LENGTH:
+       case CKA_OTP_TIME_INTERVAL:
+       case CKA_OTP_USER_FRIENDLY_MODE:
+       case CKA_OTP_CHALLENGE_REQUIREMENT:
+       case CKA_OTP_TIME_REQUIREMENT:
+       case CKA_OTP_COUNTER_REQUIREMENT:
+       case CKA_OTP_PIN_REQUIREMENT:
+       case CKA_OTP_COUNTER:
+       case CKA_OTP_TIME:
+       case CKA_OTP_USER_IDENTIFIER:
+       case CKA_OTP_SERVICE_IDENTIFIER:
+       case CKA_OTP_SERVICE_LOGO:
+       case CKA_OTP_SERVICE_LOGO_TYPE:
+*/
+       case CKA_GOSTR3410_PARAMS: return akBinary;
+       case CKA_GOSTR3411_PARAMS: return akBinary;
+       case CKA_GOST28147_PARAMS: return akBinary;
+/*
+       case CKA_HW_FEATURE_TYPE:
+       case CKA_RESET_ON_INIT:
+       case CKA_HAS_RESET:
+       case CKA_PIXEL_X:
+       case CKA_PIXEL_Y:
+       case CKA_RESOLUTION:
+       case CKA_CHAR_ROWS:
+       case CKA_CHAR_COLUMNS:
+       case CKA_COLOR:
+       case CKA_BITS_PER_PIXEL:
+       case CKA_CHAR_SETS:
+       case CKA_ENCODING_METHODS:
+       case CKA_MIME_TYPES:
+       case CKA_MECHANISM_TYPE:
+       case CKA_REQUIRED_CMS_ATTRIBUTES:
+       case CKA_DEFAULT_CMS_ATTRIBUTES:
+       case CKA_SUPPORTED_CMS_ATTRIBUTES:
+*/
+       case CKA_WRAP_TEMPLATE: return akAttrMap;
+       case CKA_UNWRAP_TEMPLATE: return akAttrMap;
+       case CKA_DERIVE_TEMPLATE: return akAttrMap;
+       case CKA_ALLOWED_MECHANISMS: return akMechSet;
+
+       case CKA_OS_TOKENLABEL: return akBinary;
+       case CKA_OS_TOKENSERIAL: return akBinary;
+       case CKA_OS_TOKENFLAGS: return akInteger;
+       case CKA_OS_SOPIN: return akBinary;
+       case CKA_OS_USERPIN: return akBinary;
+
+       default: return akUnknown;
+       }
+}
+
+static bool decodeMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& set, const unsigned char *binary, size_t size)
+{
+       for (size_t pos = 0; pos < size; )
+       {
+               // finished?
+               if (pos == size) break;
+
+               CK_MECHANISM_TYPE mechType;
+               if (pos + sizeof(mechType) > size)
+               {
+                       ERROR_MSG("mechanism type set overrun");
+                       return false;
+               }
+
+               memcpy(&mechType, binary + pos, sizeof(mechType));
+               pos += sizeof(mechType);
+
+               set.insert(mechType);
+    }
+
+       return true;
+}
+
+static void encodeMechanismTypeSet(ByteString& value, const std::set<CK_MECHANISM_TYPE>& set)
+{
+       for (std::set<CK_MECHANISM_TYPE>::const_iterator i = set.begin(); i != set.end(); ++i)
+       {
+               CK_MECHANISM_TYPE mechType = *i;
+               value += ByteString((unsigned char *) &mechType, sizeof(mechType));
+       }
+}
+
+static bool decodeAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map, const unsigned char *binary, size_t size)
+{
+       for (size_t pos = 0; pos < size; )
+       {
+               // finished?
+               if (pos == size) break;
+
+               CK_ATTRIBUTE_TYPE attrType;
+               if (pos + sizeof(attrType) > size)
+               {
+                       goto overrun;
+               }
+               memcpy(&attrType, binary + pos, sizeof(attrType));
+               pos += sizeof(attrType);
+
+               AttributeKind attrKind;
+               if (pos + sizeof(AttributeKind) > size)
+               {
+                       goto overrun;
+               }
+               memcpy(&attrKind, binary + pos, sizeof(attrKind));
+               pos += sizeof(attrKind);
+
+               // Verify using attributeKind()?
+
+               switch (attrKind)
+               {
+                       case akBoolean:
+                       {
+                               bool value;
+                               if (pos + sizeof(value) > size)
+                               {
+                                       goto overrun;
+                               }
+                               memcpy(&value, binary + pos, sizeof(value));
+                               pos += sizeof(value);
+
+                               map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
+                       }
+                       break;
+
+                       case akInteger:
+                       {
+                               unsigned long value;
+                               if (pos + sizeof(value) > size)
+                               {
+                                       goto overrun;
+                               }
+                               memcpy(&value, binary + pos, sizeof(value));
+                               pos += sizeof(value);
+
+                               map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
+                       }
+                       break;
+
+                       case akBinary:
+                       {
+                               ByteString value;
+                               unsigned long len;
+                               if (pos + sizeof(len) > size)
+                               {
+                                       goto overrun;
+                               }
+                               memcpy(&len, binary + pos, sizeof(len));
+                               pos += sizeof(len);
+
+                               if (pos + len > size)
+                               {
+                                       goto overrun;
+                               }
+                               value.resize(len);
+                               memcpy(&value[0], binary + pos, len);
+                               pos += len;
+
+                               map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
+                       }
+                       break;
+
+                       case akMechSet:
+                       {
+                               unsigned long len;
+                               if (pos + sizeof(len) > size)
+                               {
+                                       goto overrun;
+                               }
+                               memcpy(&len, binary + pos, sizeof(len));
+                               pos += sizeof(len);
+
+                               if (pos + len > size)
+                               {
+                                       goto overrun;
+                               }
+
+                               std::set<CK_MECHANISM_TYPE> value;
+                               if (!decodeMechanismTypeSet(value, binary + pos, len)) {
+                                       return false;
+                               }
+                               pos += len;
+
+                               map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
+                       }
+                       break;
+
+                       default:
+                       ERROR_MSG("unsupported attribute kind in attribute map");
+
+                       return false;
+               }
+       }
+
+       return true;
+
+overrun:
+       ERROR_MSG("attribute map template overrun");
+
+       return false;
+}
+
+static bool encodeAttributeMap(ByteString& value, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& attributes)
+{
+       for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = attributes.begin(); i != attributes.end(); ++i)
+       {
+               CK_ATTRIBUTE_TYPE attrType = i->first;
+               value += ByteString((unsigned char*) &attrType, sizeof(attrType));
+
+               OSAttribute attr = i->second;
+               if (attr.isBooleanAttribute())
+               {
+                       AttributeKind attrKind = akBoolean;
+                       value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
+
+                       bool val = attr.getBooleanValue();
+                       value += ByteString((unsigned char*) &val, sizeof(val));
+               }
+               else if (attr.isUnsignedLongAttribute())
+               {
+                       AttributeKind attrKind = akInteger;
+                       value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
+
+                       unsigned long val = attr.getUnsignedLongValue();
+                       value += ByteString((unsigned char*) &val, sizeof(val));
+               }
+               else if (attr.isByteStringAttribute())
+               {
+                       AttributeKind attrKind = akBinary;
+                       value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
+
+                       ByteString val = attr.getByteStringValue();
+                       unsigned long len = val.size();
+                       value += ByteString((unsigned char*) &len, sizeof(len));
+                       value += val;
+               }
+               else if (attr.isMechanismTypeSetAttribute())
+               {
+                       AttributeKind attrKind = akMechSet;
+                       value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
+
+                       ByteString val;
+                       encodeMechanismTypeSet(val, attr.getMechanismTypeSetValue());
+
+                       unsigned long len = val.size();
+                       value += ByteString((unsigned char*) &len, sizeof(len));
+                       value += val;
+               }
+               else
+               {
+                       ERROR_MSG("unsupported attribute kind for attribute map");
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+OSAttribute *DBObject::accessAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       switch (attributeKind(type))
+       {
+               case akUnknown:
+                       return NULL;
+               case akBoolean:
+               {
+                       // try to find the attribute in the boolean attribute table
+                       DB::Statement statement = _connection->prepare(
+                               "select value from attribute_boolean where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+                       if (!statement.isValid())
+                       {
+                               return NULL;
+                       }
+                       DB::Result result = _connection->perform(statement);
+                       if (!result.isValid())
+                       {
+                               return NULL;
+                       }
+                       // Store the attribute in the transaction when it is active.
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
+                       if (_transaction)
+                               attrs = _transaction;
+
+                       bool value = result.getInt(1) != 0;
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
+                       OSAttribute *attr;
+                       if (it != attrs->end())
+                       {
+                               if (it->second != NULL)
+                               {
+                                       delete it->second;
+                               }
+
+                               it->second = new OSAttribute(value);
+                               attr = it->second;
+                       }
+                       else
+                       {
+                               attr = new OSAttribute(value);
+                               (*attrs)[type] = attr;
+                       }
+                       return attr;
+               }
+               case akInteger:
+               {
+                       // try to find the attribute in the integer attribute table
+                       DB::Statement statement = _connection->prepare(
+                               "select value from attribute_integer where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+                       if (!statement.isValid())
+                       {
+                               return NULL;
+                       }
+                       DB::Result result = _connection->perform(statement);
+                       if (!result.isValid())
+                       {
+                               return NULL;
+                       }
+                       // Store the attribute in the transaction when it is active.
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
+                       if (_transaction)
+                               attrs = _transaction;
+
+                       unsigned long value = result.getULongLong(1);
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
+                       OSAttribute *attr;
+                       if (it != attrs->end())
+                       {
+                               if (it->second != NULL)
+                               {
+                                       delete it->second;
+                               }
+
+                               it->second = new OSAttribute(value);
+                               attr = it->second;
+                       }
+                       else
+                       {
+                               attr = new OSAttribute(value);
+                               (*attrs)[type] = attr;
+                       }
+                       return attr;
+               }
+               case akBinary:
+               {
+                       // try to find the attribute in the binary attribute table
+                       DB::Statement statement = _connection->prepare(
+                               "select value from attribute_binary where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+                       if (!statement.isValid())
+                       {
+                               return NULL;
+                       }
+                       DB::Result result = _connection->perform(statement);
+                       if (!result.isValid())
+                       {
+                               return NULL;
+                       }
+                       // Store the attribute in the transaction when it is active.
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
+                       if (_transaction)
+                               attrs = _transaction;
+
+                       const unsigned char *value = result.getBinary(1);
+                       size_t size = result.getFieldLength(1);
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
+                       OSAttribute *attr;
+                       if (it != attrs->end())
+                       {
+                               if (it->second != NULL)
+                               {
+                                       delete it->second;
+                               }
+
+                               it->second = new OSAttribute(ByteString(value,size));
+                               attr = it->second;
+                       }
+                       else
+                       {
+                               attr = new OSAttribute(ByteString(value,size));
+                               (*attrs)[type] = attr;
+                               return attr;
+                       }
+                       return attr;
+               }
+               case akMechSet:
+               {
+                       // try to find the attribute in the binary attribute table
+                       DB::Statement statement = _connection->prepare(
+                                       "select value from attribute_binary where type=%lu and object_id=%lld",
+                                       type,
+                                       _objectId);
+                       if (!statement.isValid())
+                       {
+                               return NULL;
+                       }
+                       DB::Result result = _connection->perform(statement);
+                       if (!result.isValid())
+                       {
+                               return NULL;
+                       }
+                       // Store the attribute in the transaction when it is active.
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
+                       if (_transaction)
+                               attrs = _transaction;
+
+                       const unsigned char *value = result.getBinary(1);
+                       size_t size = result.getFieldLength(1);
+
+                       std::set<CK_MECHANISM_TYPE> set;
+                       if (!decodeMechanismTypeSet(set, value, size))
+                       {
+                               return NULL;
+                       }
+
+                       OSAttribute *attr;
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
+                       if (it != attrs->end())
+                       {
+                               if (it->second != NULL)
+                               {
+                                       delete it->second;
+                               }
+
+                               it->second = new OSAttribute(set);
+                               attr = it->second;
+                       }
+                       else
+                       {
+                               attr = new OSAttribute(set);
+                               (*attrs)[type] = attr;
+                               return attr;
+                       }
+                       return attr;
+               }
+               case akAttrMap:
+               {
+                       // try to find the attribute in the array attribute table
+                       DB::Statement statement = _connection->prepare(
+                               "select value from attribute_array where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+                       if (!statement.isValid())
+                       {
+                               return NULL;
+                       }
+                       DB::Result result = _connection->perform(statement);
+                       if (!result.isValid())
+                       {
+                               return NULL;
+                       }
+                       // Store the attribute in the transaction when it is active.
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
+                       if (_transaction)
+                               attrs = _transaction;
+
+                       const unsigned char *binary = result.getBinary(1);
+                       size_t size = result.getFieldLength(1);
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
+                       OSAttribute *attr;
+                       if (it != attrs->end())
+                       {
+                               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
+                               if (!decodeAttributeMap(value,binary,size))
+                               {
+                                       return NULL;
+                               }
+
+                               if (it->second != NULL)
+                               {
+                                       delete it->second;
+                               }
+
+                               it->second = new OSAttribute(value);
+                               attr = it->second;
+                       }
+                       else
+                       {
+                               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
+                               if (!decodeAttributeMap(value,binary,size))
+                               {
+                                       return NULL;
+                               }
+                               attr = new OSAttribute(value);
+                               (*attrs)[type] = attr;
+                               return attr;
+                       }
+                       return attr;
+               }
+       }
+
+       return NULL;
+}
+
+// Retrieve the specified attribute for internal use
+// Calling function must lock the mutex
+OSAttribute* DBObject::getAttributeDB(CK_ATTRIBUTE_TYPE type)
+{
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return NULL;
+       }
+
+       if (_objectId == 0)
+       {
+               ERROR_MSG("Cannot read from invalid object.");
+               return NULL;
+       }
+
+       // If a transaction is in progress, we can just return the attribute from the transaction.
+       if (_transaction)
+       {
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
+               if (it != _transaction->end())
+                       return it->second;
+       }
+
+       // If the attribute exists and is non-modifiable then return a previously retrieved attribute value.
+       if (!isModifiable(type))
+       {
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _attributes.find(type);
+               if (it != _attributes.end())
+               {
+                       return it->second;
+               }
+       }
+
+       return accessAttribute(type);
+}
+
+// Check if the specified attribute exists
+bool DBObject::attributeExists(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(_mutex);
+
+       return getAttributeDB(type) != NULL;
+}
+
+// Retrieve the specified attribute
+OSAttribute DBObject::getAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(_mutex);
+
+       OSAttribute* attr = getAttributeDB(type);
+       if (attr == NULL) return OSAttribute((unsigned long)0);
+
+       return *attr;
+}
+
+bool DBObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
+{
+       MutexLocker lock(_mutex);
+
+       OSAttribute* attr = getAttributeDB(type);
+       if (attr == NULL) return val;
+
+       if (attr->isBooleanAttribute())
+       {
+               return attr->getBooleanValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
+               return val;
+       }
+}
+
+unsigned long DBObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
+{
+       MutexLocker lock(_mutex);
+
+       OSAttribute* attr = getAttributeDB(type);
+       if (attr == NULL) return val;
+
+       if (attr->isUnsignedLongAttribute())
+       {
+               return attr->getUnsignedLongValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
+               return val;
+       }
+}
+
+ByteString DBObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(_mutex);
+
+       ByteString val;
+
+       OSAttribute* attr = getAttributeDB(type);
+       if (attr == NULL) return val;
+
+       if (attr->isByteStringAttribute())
+       {
+               return attr->getByteStringValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
+               return val;
+       }
+}
+
+CK_ATTRIBUTE_TYPE DBObject::nextAttributeType(CK_ATTRIBUTE_TYPE)
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+       if (_objectId == 0)
+       {
+               ERROR_MSG("Cannot get next attribute for invalid object.");
+               return false;
+       }
+
+       // FIXME: implement for C_CopyObject
+       return CKA_CLASS;
+}
+
+// Set the specified attribute
+bool DBObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+       if (_objectId == 0)
+       {
+               ERROR_MSG("Cannot update invalid object.");
+               return false;
+       }
+
+       // Retrieve and existing attribute if it exists or NULL if it doesn't
+       OSAttribute *attr = getAttributeDB(type);
+
+       // Update an existing attribute...
+       if (attr)
+       {
+               DB::Statement statement;
+               if (attr->isBooleanAttribute())
+               {
+                       // update boolean attribute
+                       statement = _connection->prepare(
+                                       "update attribute_boolean set value=%d where type=%lu and object_id=%lld",
+                                       attribute.getBooleanValue() ? 1 : 0,
+                                       type,
+                                       _objectId);
+               }
+               else if (attr->isUnsignedLongAttribute())
+               {
+                       // update integer attribute
+                       statement = _connection->prepare(
+                                       "update attribute_integer set value=%lld where type=%lu and object_id=%lld",
+                                       static_cast<long long>(attribute.getUnsignedLongValue()),
+                                       type,
+                                       _objectId);
+               }
+               else if (attr->isByteStringAttribute())
+               {
+                       // update binary attribute
+                       statement = _connection->prepare(
+                                       "update attribute_binary set value=? where type=%lu and object_id=%lld",
+                                       type,
+                                       _objectId);
+                       DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
+               }
+               else if (attr->isMechanismTypeSetAttribute())
+               {
+                       // update binary attribute
+                       ByteString value;
+                       encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
+
+                       statement = _connection->prepare(
+                                       "update attribute_binary set value=? where type=%lu and object_id=%lld",
+                                       type,
+                                       _objectId);
+                       DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
+               }
+               else if (attr->isAttributeMapAttribute())
+               {
+                       // update attribute map attribute
+                       ByteString value;
+                       if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
+                       {
+                               return false;
+                       }
+
+                       statement = _connection->prepare(
+                                       "update attribute_array set value=? where type=%lu and object_id=%lld",
+                                       type,
+                                       _objectId);
+                       DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
+               }
+
+               // Statement is valid when a prepared statement has been attached to it.
+               if (statement.isValid())
+               {
+                       if (!_connection->execute(statement))
+                       {
+                               ERROR_MSG("Failed to update attribute %lu for object %lld",type,_objectId);
+                               return false;
+                       }
+
+                       if (_transaction)
+                       {
+                               std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
+                               if (it != _transaction->end())
+                                       *it->second = attribute;
+                               else
+                                       (*_transaction)[type] = new OSAttribute(attribute);
+                       } else
+                               *attr = attribute;
+                       return true;
+               }
+       }
+
+       DB::Statement statement;
+
+       // Insert the attribute, because it is currently unknown
+       if (attribute.isBooleanAttribute())
+       {
+               // Could not update it, so we need to insert it.
+               statement = _connection->prepare(
+                                       "insert into attribute_boolean (value,type,object_id) values (%d,%lu,%lld)",
+                                       attribute.getBooleanValue() ? 1 : 0,
+                                       type,
+                                       _objectId);
+
+       }
+       else if (attribute.isUnsignedLongAttribute())
+       {
+               // Could not update it, so we need to insert it.
+               statement = _connection->prepare(
+                                       "insert into attribute_integer (value,type,object_id) values (%lld,%lu,%lld)",
+                                       static_cast<long long>(attribute.getUnsignedLongValue()),
+                                       type,
+                                       _objectId);
+       }
+       else if (attribute.isByteStringAttribute())
+       {
+               // Could not update it, so we need to insert it.
+               statement = _connection->prepare(
+                                       "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
+                                       type,
+                                       _objectId);
+
+               DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
+       }
+       else if (attribute.isMechanismTypeSetAttribute())
+       {
+               // Could not update it, so we need to insert it.
+               ByteString value;
+               encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
+
+               statement = _connection->prepare(
+                               "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
+                               type,
+                               _objectId);
+               DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
+       }
+       else if (attribute.isAttributeMapAttribute())
+       {
+               // Could not update it, so we need to insert it.
+               ByteString value;
+               if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
+               {
+                       return false;
+               }
+
+               statement = _connection->prepare(
+                               "insert into attribute_array (value,type,object_id) values (?,%lu,%lld)",
+                               type,
+                               _objectId);
+               DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
+       }
+
+       // Statement is valid when a prepared statement has been attached to it.
+       if (statement.isValid())
+       {
+               if (!_connection->execute(statement))
+               {
+                       ERROR_MSG("Failed to insert attribute %lu for object %lld",type,_objectId);
+                       return false;
+               }
+
+               if (_transaction)
+                       (*_transaction)[type] = new OSAttribute(attribute);
+               else
+                       _attributes[type] = new OSAttribute(attribute);
+               return true;
+       }
+
+       return false;
+}
+
+// Set the specified attribute
+bool DBObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+       if (_objectId == 0)
+       {
+               ERROR_MSG("Cannot update invalid object.");
+               return false;
+       }
+
+       // Retrieve and existing attribute if it exists or NULL if it doesn't
+       OSAttribute *attr = getAttributeDB(type);
+       if (attr == NULL)
+       {
+               ERROR_MSG("Cannot delete an attribute that doesn't exist.");
+               return false;
+       }
+
+       DB::Statement statement;
+       if (attr->isBooleanAttribute())
+       {
+               // delete boolean attribute
+               statement = _connection->prepare(
+                               "delete from attribute_boolean where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+       }
+       else if (attr->isUnsignedLongAttribute())
+       {
+               // delete integer attribute
+               statement = _connection->prepare(
+                               "delete from attribute_integer where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+       }
+       else if (attr->isByteStringAttribute() || attr -> isMechanismTypeSetAttribute())
+       {
+               // delete binary attribute
+               statement = _connection->prepare(
+                               "delete from attribute_binary where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+       }
+       else if (attr->isAttributeMapAttribute())
+       {
+               // delete attribute map attribute
+               statement = _connection->prepare(
+                               "delete from attribute_array where type=%lu and object_id=%lld",
+                               type,
+                               _objectId);
+       }
+
+       // Statement is valid when a prepared statement has been attached to it.
+       if (statement.isValid())
+       {
+               if (!_connection->execute(statement))
+               {
+                       ERROR_MSG("Failed to delete attribute %lu for object %lld",type,_objectId);
+                       return false;
+               }
+
+               if (_transaction)
+               {
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
+                       if (it != _transaction->end())
+                       {
+                               delete it->second;
+                               it->second = NULL;
+                       }
+               }
+
+               return true;
+       }
+
+       return false;
+}
+
+// The validity state of the object
+bool DBObject::isValid()
+{
+       MutexLocker lock(_mutex);
+
+       return _objectId != 0 && _connection != NULL;
+}
+
+// Start an attribute set transaction; this method is used when - for
+// example - a key is generated and all its attributes need to be
+// persisted in one go.
+//
+// N.B.: Starting a transaction locks the object!
+bool DBObject::startTransaction(Access access)
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       if (_transaction)
+       {
+               ERROR_MSG("Transaction is already active.");
+               return false;
+       }
+
+       _transaction = new std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>;
+       if (_transaction == NULL)
+       {
+               ERROR_MSG("Not enough memory to start transaction.");
+               return false;
+       }
+
+       if (_connection->inTransaction())
+       {
+               ERROR_MSG("Transaction in database is already active.");
+               return false;
+       }
+
+       // Ask the connection to start the transaction.
+       if (access == ReadWrite)
+               return _connection->beginTransactionRW();
+       else
+               return _connection->beginTransactionRO();
+}
+
+// Commit an attribute transaction
+bool DBObject::commitTransaction()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       if (_transaction == NULL)
+       {
+               ERROR_MSG("No transaction active.");
+               return false;
+       }
+
+       if (!_connection->commitTransaction())
+       {
+               return false;
+       }
+
+       // Copy the values from the internally stored transaction to the _attributes field.
+       for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator attr_it = _attributes.find(it->first);
+               if (attr_it == _attributes.end())
+               {
+                       _attributes[it->first] = it->second;
+               }
+               else
+               {
+                       *attr_it->second = *it->second;
+                       delete it->second;
+               }
+               it->second = NULL;
+       }
+       delete _transaction;
+       _transaction = NULL;
+       return true;
+}
+
+// Abort an attribute transaction; loads back the previous version of the object from disk
+bool DBObject::abortTransaction()
+{
+       MutexLocker lock(_mutex);
+
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Object is not connected to the database.");
+               return false;
+       }
+
+       // Forget the atributes that were set during the transaction.
+       if (_transaction)
+       {
+               for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
+                       delete it->second;
+                       it->second = NULL;
+               }
+               delete _transaction;
+               _transaction = NULL;
+       }
+
+       return _connection->rollbackTransaction();
+}
+
+// Destroy the object; WARNING: pointers to the object become invalid after this call
+bool DBObject::destroyObject()
+{
+       // NOTE: Do not lock _mutex, because _token will call us back and cause a deadlock.
+       // There is no need to lock anyway as _token is a non-mutable pointer, so no race
+       // conditions possible.
+
+       if (_token == NULL)
+       {
+               ERROR_MSG("Cannot destroy an object that is not associated with a token");
+               return false;
+       }
+
+       return _token->deleteObject(this);
+}
diff --git a/SoftHSMv2/src/lib/object_store/DBObject.h b/SoftHSMv2/src/lib/object_store/DBObject.h
new file mode 100644 (file)
index 0000000..4dc1249
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObject.h
+
+ This class represents object records in a database
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBOBJECT_H
+#define _SOFTHSM_V2_DBOBJECT_H
+
+#include "config.h"
+#include "OSAttribute.h"
+#include "cryptoki.h"
+#include "OSObject.h"
+#include "ObjectStoreToken.h"
+
+#include "MutexFactory.h"
+#include <string>
+
+namespace DB { class Connection;  }
+
+class DBObject : public OSObject
+{
+public:
+       // Constructor for creating or accessing an object, don't do anything yet.
+       DBObject(DB::Connection *connection, ObjectStoreToken *token = NULL);
+
+       // Constructor for accessing an object with an objectId known to exists
+       DBObject(DB::Connection *connection, ObjectStoreToken *token, long long objectId);
+
+       // Destructor
+       virtual ~DBObject();
+
+       // Will drop any internal references to the connection
+       void dropConnection();
+
+       // create tables to support storage of attributes for the object.
+       bool createTables();
+
+       // drop tables that support storage of attributes for the object.
+       bool dropTables();
+
+       // Find an existing object.
+       bool find(long long objectId);
+
+       // Insert a new object into the database and retrieve the object id associated with it.
+       bool insert();
+
+       // Remove an existing object from the database and reset the object id to zero.
+       bool remove();
+
+       // Object id associated with this object.
+       long long objectId();
+
+       // Check if the specified attribute exists
+       virtual bool attributeExists(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the specified attribute
+       virtual OSAttribute getAttribute(CK_ATTRIBUTE_TYPE type);
+       virtual bool getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val);
+       virtual unsigned long getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val);
+       virtual ByteString getByteStringValue(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the next attribute type
+       virtual CK_ATTRIBUTE_TYPE nextAttributeType(CK_ATTRIBUTE_TYPE type);
+
+       // Set the specified attribute
+       virtual bool setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute);
+
+       // Delete the specified attribute
+       virtual bool deleteAttribute(CK_ATTRIBUTE_TYPE type);
+
+       // The validity state of the object
+       virtual bool isValid();
+
+       // Start an attribute set transaction; this method is used when - for
+       // example - a key is generated and all its attributes need to be
+       // persisted in one go.
+       //
+       // N.B.: Starting a transaction locks the object!
+       //
+       // Function returns false in case a transaction is already in progress
+       virtual bool startTransaction(Access access);
+
+       // Commit an attribute transaction; returns false if no transaction is in progress
+       virtual bool commitTransaction();
+
+       // Abort an attribute transaction; loads back the previous version of the object from disk;
+       // returns false if no transaction was in progress
+       virtual bool abortTransaction();
+
+       // Destroys the object (warning, any pointers to the object are no longer
+       // valid after this call because delete is called!)
+       virtual bool destroyObject();
+
+private:
+       // Disable copy constructor and assignment
+       DBObject();
+       DBObject(const DBObject&);
+       DBObject & operator= (const DBObject &);
+
+       // Mutex object for thread-safeness
+       Mutex* _mutex;
+
+       DB::Connection *_connection;
+       ObjectStoreToken *_token;
+       long long _objectId;
+
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> _attributes;
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *_transaction;
+
+       OSAttribute* getAttributeDB(CK_ATTRIBUTE_TYPE type);
+       OSAttribute* accessAttribute(CK_ATTRIBUTE_TYPE type);
+};
+
+#endif // !_SOFTHSM_V2_DBOBJECT_H
+
diff --git a/SoftHSMv2/src/lib/object_store/DBToken.cpp b/SoftHSMv2/src/lib/object_store/DBToken.cpp
new file mode 100644 (file)
index 0000000..e734372
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBToken.cpp
+ The token class; a token is stored in a directory containing a single
+ database file.
+ Each object is stored in multiple tables with every attribute base type
+ stored in a different table.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSAttributes.h"
+#include "OSAttribute.h"
+#include "OSPathSep.h"
+
+#include "cryptoki.h"
+#include "DBToken.h"
+#include "DBObject.h"
+#include "DB.h"
+
+#include "Directory.h"
+
+#include <vector>
+#include <string>
+#include <set>
+#include <map>
+#include <list>
+#include <cstdio>
+#include <sys/stat.h>
+#include <errno.h>
+
+const char * const DBTOKEN_FILE = "sqlite3.db";
+const long long DBTOKEN_OBJECT_TOKENINFO = 1;
+
+// Constructor for creating a new token.
+DBToken::DBToken(const std::string &baseDir, const std::string &tokenName, const ByteString &label, const ByteString &serial)
+       : _connection(NULL), _tokenMutex(NULL)
+{
+       std::string tokenDir = baseDir + OS_PATHSEP + tokenName;
+       std::string tokenPath = tokenDir + OS_PATHSEP + DBTOKEN_FILE;
+
+       // Refuse to open an already existing database.
+       FILE *f = fopen(tokenPath.c_str(),"r");
+       if (f)
+       {
+               fclose(f);
+               ERROR_MSG("Refusing to overwrite and existing database at \"%s\"", tokenPath.c_str());
+               return;
+       }
+
+       // First create the directory for the token, we expect basePath to already exist
+       if (mkdir(tokenDir.c_str(), S_IFDIR | S_IRWXU))
+       {
+               // Allow the directory to exists already.
+               if (errno != EEXIST)
+               {
+                       ERROR_MSG("Unable to create directory \"%s\"", tokenDir.c_str());
+                       return;
+               }
+       }
+
+       // Create
+       _connection = DB::Connection::Create(tokenDir, DBTOKEN_FILE);
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Failed to create a database connection for \"%s\"", tokenPath.c_str());
+               return;
+       }
+
+       if (!_connection->connect())
+       {
+               delete _connection;
+               _connection = NULL;
+
+               ERROR_MSG("Failed to connect to the database at \"%s\"", tokenPath.c_str());
+
+               // Now remove the token directory
+               if (remove(tokenDir.c_str()))
+               {
+                       ERROR_MSG("Failed to remove the token directory \"%s\"", tokenDir.c_str());
+               }
+
+               return;
+       }
+
+       // Create a DBObject for the established connection to the database.
+       DBObject tokenObject(_connection);
+
+       // First create the tables that support storage of object attributes and then insert the object containing
+       // the token info into the database.
+       if (!tokenObject.createTables() || !tokenObject.insert() || tokenObject.objectId()!=DBTOKEN_OBJECT_TOKENINFO)
+       {
+               tokenObject.dropConnection();
+
+               _connection->close();
+               delete _connection;
+               _connection = NULL;
+
+               ERROR_MSG("Failed to create tables for storing objects in database at \"%s\"", tokenPath.c_str());
+               return;
+       }
+
+       // Set the initial attributes
+       CK_ULONG flags =
+               CKF_RNG |
+               CKF_LOGIN_REQUIRED | // FIXME: check
+               CKF_RESTORE_KEY_NOT_NEEDED |
+               CKF_TOKEN_INITIALIZED |
+               CKF_SO_PIN_LOCKED |
+               CKF_SO_PIN_TO_BE_CHANGED;
+
+       OSAttribute tokenLabel(label);
+       OSAttribute tokenSerial(serial);
+       OSAttribute tokenFlags(flags);
+
+       if (!tokenObject.setAttribute(CKA_OS_TOKENLABEL, tokenLabel) ||
+               !tokenObject.setAttribute(CKA_OS_TOKENSERIAL, tokenSerial) ||
+               !tokenObject.setAttribute(CKA_OS_TOKENFLAGS, tokenFlags))
+       {
+               _connection->close();
+               delete _connection;
+               _connection = NULL;
+
+               // Now remove the token file
+               if (remove(tokenPath.c_str()))
+               {
+                       ERROR_MSG("Failed to remove the token file at \"%s\"", tokenPath.c_str());
+               }
+
+               // Now remove the token directory
+               if (remove(tokenDir.c_str()))
+               {
+                       ERROR_MSG("Failed to remove the token directory at \"%s\"", tokenDir.c_str());
+               }
+               return;
+       }
+
+       _tokenMutex = MutexFactory::i()->getMutex();
+       // Success!
+}
+
+// Constructor for accessing an existing token.
+DBToken::DBToken(const std::string &baseDir, const std::string &tokenName)
+       : _connection(NULL), _tokenMutex(NULL)
+{
+       std::string tokenDir = baseDir + OS_PATHSEP + tokenName;
+       std::string tokenPath = tokenDir + OS_PATHSEP + DBTOKEN_FILE;
+
+       // Refuse to open an already existing database.
+       FILE *f = fopen(tokenPath.c_str(),"r");
+       if (f == NULL)
+       {
+               ERROR_MSG("Refusing to open a non-existant database at \"%s\"", tokenPath.c_str());
+               return;
+       }
+       fclose(f);
+
+       // Create a database connection.
+       _connection = DB::Connection::Create(tokenDir, DBTOKEN_FILE);
+       if (_connection == NULL)
+       {
+               ERROR_MSG("Failed to create a database connection for \"%s\"", tokenPath.c_str());
+               return;
+       }
+
+       if (!_connection->connect())
+       {
+               delete _connection;
+               _connection = NULL;
+
+               ERROR_MSG("Failed to connect to the database at \"%s\"", tokenPath.c_str());
+
+               return;
+       }
+
+       // Find the DBObject for the established connection to the database.
+       DBObject tokenObject(_connection);
+
+       // First find the token obect that indicates the token is properly initialized.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               tokenObject.dropConnection();
+
+               _connection->close();
+               delete _connection;
+               _connection = NULL;
+
+               ERROR_MSG("Failed to open token object in the token database at \"%s\"", tokenPath.c_str());
+               return;
+       }
+
+       _tokenMutex = MutexFactory::i()->getMutex();
+
+       // Success!
+}
+
+DBToken *DBToken::createToken(const std::string basePath, const std::string tokenDir, const ByteString &label, const ByteString &serial)
+{
+       Directory baseDir(basePath);
+
+       if (!baseDir.isValid())
+       {
+               return NULL;
+       }
+
+       // Create the token directory
+       if (!baseDir.mkdir(tokenDir))
+       {
+               return NULL;
+       }
+
+       DBToken *token = new DBToken(basePath, tokenDir, label, serial);
+       if (!token->isValid())
+       {
+               baseDir.rmdir(tokenDir);
+
+               delete token;
+               return NULL;
+       }
+
+       DEBUG_MSG("Created new token %s", tokenDir.c_str());
+
+       return token;
+}
+
+DBToken *DBToken::accessToken(const std::string &basePath, const std::string &tokenDir)
+{
+       return new DBToken(basePath, tokenDir);
+}
+
+// Destructor
+DBToken::~DBToken()
+{
+       if (_tokenMutex)
+       {
+               MutexFactory::i()->recycleMutex(_tokenMutex);
+               _tokenMutex = NULL;
+       }
+
+       std::map<long long, OSObject*> cleanUp = _allObjects;
+       _allObjects.clear();
+       for (std::map<long long, OSObject*>::iterator i = cleanUp.begin(); i != cleanUp.end(); ++i)
+       {
+               delete i->second;
+       }
+
+       if (_connection)
+       {
+               delete _connection;
+               _connection = NULL;
+       }
+}
+
+// Set the SO PIN
+bool DBToken::setSOPIN(const ByteString& soPINBlob)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadWrite))
+       {
+               ERROR_MSG("Unable to start a transaction for updating the SOPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       OSAttribute soPIN(soPINBlob);
+       if (!tokenObject.setAttribute(CKA_OS_SOPIN, soPIN))
+       {
+               ERROR_MSG("Error while setting SOPIN in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS))
+       {
+               ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN.
+       CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue()
+                                       & ~(CKF_SO_PIN_COUNT_LOW | CKF_SO_PIN_FINAL_TRY | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED);
+
+       OSAttribute changedTokenFlags(flags);
+       if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags))
+       {
+               ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.commitTransaction())
+       {
+               ERROR_MSG("Error while committing SOPIN and TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       return true;
+}
+
+// Get the SO PIN
+bool DBToken::getSOPIN(ByteString& soPINBlob)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadOnly))
+       {
+               ERROR_MSG("Unable to start a transaction for getting the SOPIN from token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_SOPIN))
+       {
+               ERROR_MSG("Error while getting SOPIN from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       tokenObject.commitTransaction();
+       soPINBlob = tokenObject.getAttribute(CKA_OS_SOPIN).getByteStringValue();
+       return true;
+}
+
+// Set the user PIN
+bool DBToken::setUserPIN(ByteString userPINBlob)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadWrite))
+       {
+               ERROR_MSG("Unable to start a transaction for updating the USERPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       OSAttribute userPIN(userPINBlob);
+       if (!tokenObject.setAttribute(CKA_OS_USERPIN, userPIN))
+       {
+               ERROR_MSG("Error while setting USERPIN in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS))
+       {
+               ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN.
+       CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue()
+                                       | (CKF_USER_PIN_INITIALIZED & ~(CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_LOCKED | CKF_USER_PIN_TO_BE_CHANGED));
+
+       OSAttribute changedTokenFlags(flags);
+       if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags))
+       {
+               ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.commitTransaction())
+       {
+               ERROR_MSG("Error while committing USERPIN and TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       return true;
+}
+
+// Get the user PIN
+bool DBToken::getUserPIN(ByteString& userPINBlob)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadOnly))
+       {
+               ERROR_MSG("Unable to start a transaction for getting the USERPIN from token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_USERPIN))
+       {
+               ERROR_MSG("Error while getting USERPIN from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       tokenObject.commitTransaction();
+       userPINBlob = tokenObject.getAttribute(CKA_OS_USERPIN).getByteStringValue();
+       return true;
+}
+
+// Retrieve the token label
+bool DBToken::getTokenLabel(ByteString& label)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadOnly))
+       {
+               ERROR_MSG("Unable to start a transaction for getting the TOKENLABEL from token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENLABEL))
+       {
+               ERROR_MSG("Error while getting TOKENLABEL from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       tokenObject.commitTransaction();
+       label = tokenObject.getAttribute(CKA_OS_TOKENLABEL).getByteStringValue();
+       return true;
+}
+
+// Retrieve the token serial
+bool DBToken::getTokenSerial(ByteString& serial)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadOnly))
+       {
+               ERROR_MSG("Unable to start a transaction for getting the TOKENSERIAL from token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENSERIAL))
+       {
+               ERROR_MSG("Error while getting TOKENSERIAL from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       tokenObject.commitTransaction();
+       serial = tokenObject.getAttribute(CKA_OS_TOKENSERIAL).getByteStringValue();
+       return true;
+}
+
+// Get the token flags
+bool DBToken::getTokenFlags(CK_ULONG& flags)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadOnly))
+       {
+               ERROR_MSG("Unable to start a transaction for updating the SOPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS))
+       {
+               ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       tokenObject.commitTransaction();
+       flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue();
+       return true;
+}
+
+// Set the token flags
+bool DBToken::setTokenFlags(const CK_ULONG flags)
+{
+       if (_connection == NULL) return false;
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadWrite))
+       {
+               ERROR_MSG("Unable to start a transaction for setting the TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       OSAttribute tokenFlags(flags);
+       if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, tokenFlags))
+       {
+               ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.commitTransaction())
+       {
+               ERROR_MSG("Error while committing TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       return true;
+}
+
+// Retrieve objects
+std::set<OSObject *> DBToken::getObjects()
+{
+       std::set<OSObject*> objects;
+       getObjects(objects);
+       return objects;
+}
+
+void DBToken::getObjects(std::set<OSObject*> &objects)
+{
+       if (_connection == NULL) return;
+
+       if (!_connection->beginTransactionRO()) return;
+
+       DB::Statement statement = _connection->prepare("select id from object limit -1 offset 1");
+
+       DB::Result result = _connection->perform(statement);
+
+       if (result.isValid())
+       {
+               do {
+                       long long objectId = result.getLongLong(1);
+                       {
+                               MutexLocker lock(_tokenMutex);
+                               std::map<long long, OSObject*>::iterator it = _allObjects.find(objectId);
+                               if (it == _allObjects.end())
+                               {
+                                       DBObject *object = new DBObject(_connection, this, objectId);
+                                       _allObjects[objectId] = object;
+                                       objects.insert(object);
+                               }
+                               else
+                               {
+                                       objects.insert(it->second);
+                               }
+                       }
+               } while (result.nextRow());
+       }
+
+       _connection->endTransactionRO();
+}
+
+// Create a new object
+OSObject *DBToken::createObject()
+{
+       if (_connection == NULL) return NULL;
+
+       DBObject *newObject = new DBObject(_connection, this);
+       if (newObject == NULL)
+       {
+               ERROR_MSG("Failed to create an object: out of memory");
+               return NULL;
+       }
+
+       if (!newObject->startTransaction(DBObject::ReadWrite))
+       {
+               delete newObject;
+               ERROR_MSG("Unable to start a transaction in token database at \"%s\"", _connection->dbpath().c_str());
+               return NULL;
+       }
+
+       if (!newObject->insert())
+       {
+               newObject->abortTransaction();
+               delete newObject;
+               ERROR_MSG("Unable to insert an object into token database at \"%s\"", _connection->dbpath().c_str());
+               return NULL;
+       }
+
+       if (!newObject->isValid())
+       {
+               newObject->abortTransaction();
+               delete newObject;
+               ERROR_MSG("Object that was inserted in not valid");
+               return NULL;
+       }
+
+       if (!newObject->commitTransaction())
+       {
+               newObject->abortTransaction();
+               delete newObject;
+               ERROR_MSG("Unable to commit a created object to token database at \"%s\"", _connection->dbpath().c_str());
+               return NULL;
+       }
+
+       // Now add the new object to the list of existing objects.
+       {
+               MutexLocker lock(_tokenMutex);
+               _allObjects[newObject->objectId()] = newObject;
+       }
+
+       return newObject;
+}
+
+bool DBToken::deleteObject(OSObject *object)
+{
+       if (_connection == NULL) return false;
+
+       if (object == NULL)
+       {
+               ERROR_MSG("Object passed in as a parameter is NULL");
+               return false;
+       }
+
+       if (!object->startTransaction(DBObject::ReadWrite))
+       {
+               ERROR_MSG("Unable to start a transaction for deleting an object in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       if (!static_cast<DBObject *>(object)->remove())
+       {
+               ERROR_MSG("Error while deleting an existing object from the token database at \"%s\"", _connection->dbpath().c_str());
+               object->abortTransaction();
+               return false;
+       }
+
+       if (!object->commitTransaction())
+       {
+               ERROR_MSG("Error while committing the deletion of an existing object in token database at \"%s\"", _connection->dbpath().c_str());
+               object->abortTransaction();
+               return false;
+       }
+
+       return true;
+}
+
+// Checks if the token is consistent
+bool DBToken::isValid()
+{
+       return _connection != NULL && _connection->tableExists("object");
+}
+
+// Invalidate the token (for instance if it is deleted)
+void DBToken::invalidate()
+{
+}
+
+// Delete the token.
+bool DBToken::clearToken()
+{
+       if (_connection == NULL) return false;
+
+       std::string tokenDir = _connection->dbdir();
+       std::string tokenPath = _connection->dbpath();
+
+       if (!DBObject(_connection).dropTables())
+       {
+               ERROR_MSG("Failed to drop all tables in the token database at \"%s\"", tokenPath.c_str());
+               return false;
+       }
+
+       _connection->close();
+       delete _connection;
+       _connection = NULL;
+
+       // Remove all files from the token directory, even ones not placed there by us.
+       Directory dir(tokenDir);
+       std::vector<std::string> tokenFiles = dir.getFiles();
+
+       for (std::vector<std::string>::iterator i = tokenFiles.begin(); i != tokenFiles.end(); i++)
+       {
+               if (!dir.remove(*i))
+               {
+                       ERROR_MSG("Failed to remove \"%s\" from token directory \"%s\"", i->c_str(), tokenDir.c_str());
+
+                       return false;
+               }
+       }
+
+       // Now remove the token directory
+       if (!dir.rmdir(""))
+       {
+               ERROR_MSG("Failed to remove the token directory \"%s\"", tokenDir.c_str());
+
+               return false;
+       }
+
+       DEBUG_MSG("Token instance %s was succesfully cleared", tokenDir.c_str());
+
+       return true;
+}
+
+// Reset the token
+bool DBToken::resetToken(const ByteString& label)
+{
+       if (_connection == NULL) return false;
+
+       std::string tokenDir = _connection->dbdir();
+
+       // Clean up
+       std::set<OSObject*> cleanUp = getObjects();
+
+       for (std::set<OSObject*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               if (!deleteObject(*i))
+               {
+                       ERROR_MSG("Unable to delete all objects in token database at \"%s\"", _connection->dbpath().c_str());
+                       return false;
+               }
+       }
+
+       // Create a DBObject for the established connection to the token object in the database
+       DBObject tokenObject(_connection);
+
+       if (!tokenObject.startTransaction(DBObject::ReadWrite))
+       {
+               ERROR_MSG("Unable to start a transaction for setting the TOKENLABEL in token database at \"%s\"", _connection->dbpath().c_str());
+               return false;
+       }
+
+       // First find the token object in the database.
+       if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO))
+       {
+               ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (tokenObject.attributeExists(CKA_OS_USERPIN))
+       {
+               if (!tokenObject.deleteAttribute(CKA_OS_USERPIN))
+               {
+                       ERROR_MSG("Error while deleting USERPIN in token database at \"%s\"", _connection->dbpath().c_str());
+                       tokenObject.abortTransaction();
+                       return false;
+               }
+       }
+
+       if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS))
+       {
+               ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN.
+       CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue()
+                                       & ~(CKF_USER_PIN_INITIALIZED | CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_LOCKED | CKF_USER_PIN_TO_BE_CHANGED);
+
+       OSAttribute changedTokenFlags(flags);
+       if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags))
+       {
+               ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       OSAttribute tokenLabel(label);
+       if (!tokenObject.setAttribute(CKA_OS_TOKENLABEL, tokenLabel))
+       {
+               ERROR_MSG("Error while setting TOKENLABEL in token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       if (!tokenObject.commitTransaction())
+       {
+               ERROR_MSG("Error while committing TOKENLABEL changes to token database at \"%s\"", _connection->dbpath().c_str());
+               tokenObject.abortTransaction();
+               return false;
+       }
+
+       DEBUG_MSG("Token instance %s was succesfully reset", tokenDir.c_str());
+
+       return true;
+}
diff --git a/SoftHSMv2/src/lib/object_store/DBToken.h b/SoftHSMv2/src/lib/object_store/DBToken.h
new file mode 100644 (file)
index 0000000..ef4c28e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBToken.h
+
+ The token class; a token is stored in a directory containing a single
+ database file.
+ Each object is stored in multiple tables with every attribute base type
+ stored in a different table.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBTOKEN_H
+#define _SOFTHSM_V2_DBTOKEN_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "MutexFactory.h"
+#include "OSAttribute.h"
+#include "cryptoki.h"
+#include "OSObject.h"
+#include "ObjectStoreToken.h"
+
+#include <string>
+#include <set>
+
+namespace DB { class Connection; }
+
+class DBToken : public ObjectStoreToken
+{
+public:
+       // Constructor to create a new token
+       DBToken(const std::string &baseDir, const std::string &tokenName, const ByteString& label, const ByteString& serial);
+
+       // Constructor to access an existing token
+       DBToken(const std::string &baseDir, const std::string &tokenName);
+
+       // Create a new token
+       static DBToken* createToken(const std::string basePath, const std::string tokenDir, const ByteString& label, const ByteString& serial);
+
+       // Access an existing token
+       static DBToken* accessToken(const std::string &basePath, const std::string &tokenDir);
+
+       // Destructor
+       virtual ~DBToken();
+
+       // Set the SO PIN
+       virtual bool setSOPIN(const ByteString& soPINBlob);
+
+       // Get the SO PIN
+       virtual bool getSOPIN(ByteString& soPINBlob);
+
+       // Set the user PIN
+       virtual bool setUserPIN(ByteString userPINBlob);
+
+       // Get the user PIN
+       virtual bool getUserPIN(ByteString& userPINBlob);
+
+       // Get the token flags
+       virtual bool getTokenFlags(CK_ULONG& flags);
+
+       // Set the token flags
+       virtual bool setTokenFlags(const CK_ULONG flags);
+
+       // Retrieve the token label
+       virtual bool getTokenLabel(ByteString& label);
+
+       // Retrieve the token serial
+       virtual bool getTokenSerial(ByteString& serial);
+
+       // Retrieve objects
+       virtual std::set<OSObject*> getObjects();
+
+       // Insert objects into the given set
+       virtual void getObjects(std::set<OSObject*> &objects);
+
+       // Create a new object
+       virtual OSObject* createObject();
+
+       // Delete an object
+       virtual bool deleteObject(OSObject* object);
+
+       // Checks if the token is consistent
+       virtual bool isValid();
+
+       // Invalidate the token (for instance if it is deleted)
+       virtual void invalidate();
+
+       // Delete the token
+       virtual bool clearToken();
+
+       // Reset the token
+       virtual bool resetToken(const ByteString& label);
+
+private:
+       DB::Connection *_connection;
+
+       // All the objects ever associated with this token
+       //
+       // This map is kept to be able to clean up when the token
+       // instance is discarded; in case the contents of a token
+       // change, some objects may disappear but we cannot simply
+       // delete them since they may still be referenced from an
+       // object outside of this class.
+       std::map<long long, OSObject*> _allObjects;
+
+       // For thread safeness
+       Mutex* _tokenMutex;
+};
+
+#endif // !_SOFTHSM_V2_DBTOKEN_H
+
diff --git a/SoftHSMv2/src/lib/object_store/Directory.cpp b/SoftHSMv2/src/lib/object_store/Directory.cpp
new file mode 100644 (file)
index 0000000..e964d32
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ Directory.cpp
+
+ Helper functions for accessing directories.
+ *****************************************************************************/
+
+#include "config.h"
+#include "Directory.h"
+#include "OSPathSep.h"
+#include "log.h"
+#include <string>
+#include <vector>
+#ifndef _WIN32
+#include <dirent.h>
+#include <unistd.h>
+#else
+#include <direct.h>
+#include <io.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// Constructor
+Directory::Directory(std::string inPath)
+{
+       path = inPath;
+       dirMutex = MutexFactory::i()->getMutex();
+
+       valid = (dirMutex != NULL) && refresh();
+}
+
+// Destructor
+Directory::~Directory()
+{
+       MutexFactory::i()->recycleMutex(dirMutex);
+}
+
+// Check if the directory is valid
+bool Directory::isValid()
+{
+       return valid;
+}
+
+// Return a list of all files in a directory
+std::vector<std::string> Directory::getFiles()
+{
+       // Make sure that no other thread is in the process of changing
+       // the file list when we return it
+       MutexLocker lock(dirMutex);
+
+       return files;
+}
+
+// Return a list of all subdirectories in a directory
+std::vector<std::string> Directory::getSubDirs()
+{
+       // Make sure that no other thread is in the process of changing
+       // the subdirectory list when we return it
+       MutexLocker lock(dirMutex);
+
+       return subDirs;
+}
+
+// Refresh the directory listing
+bool Directory::refresh()
+{
+       // Prevent concurrent call until valid is reset
+       MutexLocker lock(dirMutex);
+
+       // Reset the state
+       valid = false;
+
+       subDirs.clear();
+       files.clear();
+
+#ifndef _WIN32
+       // Enumerate the directory
+       DIR* dir = opendir(path.c_str());
+
+       if (dir == NULL)
+       {
+               DEBUG_MSG("Failed to open directory %s", path.c_str());
+
+               return false;
+       }
+
+       // Enumerate the directory
+       struct dirent* entry = NULL;
+
+       while ((entry = readdir(dir)) != NULL)
+       {
+               bool pushed = false;
+
+               // Check if this is the . or .. entry
+               if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+               {
+                       continue;
+               }
+
+               // Convert the name of the entry to a C++ string
+               std::string name(entry->d_name);
+
+#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE)
+               // Determine the type of the entry
+               switch(entry->d_type)
+               {
+               case DT_DIR:
+                       // This is a directory
+                       subDirs.push_back(name);
+                       pushed = true;
+                       break;
+               case DT_REG:
+                       // This is a regular file
+                       files.push_back(name);
+                       pushed = true;
+                       break;
+               default:
+                       break;
+               }
+#endif
+               if (!pushed) {
+                       // The entry type has to be determined using lstat
+                       struct stat entryStatus;
+
+                       std::string fullPath = path + OS_PATHSEP + name;
+
+                       if (!lstat(fullPath.c_str(), &entryStatus))
+                       {
+                               if (S_ISDIR(entryStatus.st_mode))
+                               {
+                                       subDirs.push_back(name);
+                               }
+                               else if (S_ISREG(entryStatus.st_mode))
+                               {
+                                       files.push_back(name);
+                               }
+                               else
+                               {
+                                       DEBUG_MSG("File not used %s", name.c_str());
+                               }
+                       }
+               }
+       }
+
+       // Close the directory
+       closedir(dir);
+
+#else
+       // Enumerate the directory
+       std::string pattern;
+       intptr_t h;
+       struct _finddata_t fi;
+
+       if ((path.back() == '/') || (path.back() == '\\'))
+               pattern = path + "*";
+       else
+               pattern = path + "/*";
+       memset(&fi, 0, sizeof(fi));
+       h = _findfirst(pattern.c_str(), &fi);
+       if (h == -1)
+       {
+               // empty directory
+               if (errno == ENOENT)
+                       goto finished;
+
+               DEBUG_MSG("Failed to open directory %s", path.c_str());
+
+               return false;
+       }
+
+       // scan files & subdirs
+       do {
+               // Check if this is the . or .. entry
+               if (!strcmp(fi.name, ".") || !strcmp(fi.name, ".."))
+                       continue;
+
+               if ((fi.attrib & _A_SUBDIR) == 0)
+                       files.push_back(fi.name);
+               else
+                       subDirs.push_back(fi.name);
+
+               memset(&fi, 0, sizeof(fi));
+       } while (_findnext(h, &fi) == 0);
+
+       (void) _findclose(h);
+
+    finished:
+#endif
+
+       valid = true;
+
+       return true;
+}
+
+// Create a new subdirectory
+bool Directory::mkdir(std::string name)
+{
+       std::string fullPath = path + OS_PATHSEP + name;
+
+#ifndef _WIN32
+       int rv = ::mkdir(fullPath.c_str(), S_IFDIR | S_IRWXU);
+#else
+       int rv = _mkdir(fullPath.c_str());
+#endif
+
+       if (rv != 0)
+       {
+               ERROR_MSG("Failed to create the directory (%s): %s", strerror(errno), fullPath.c_str());
+
+               return false;
+       }
+
+       return refresh();
+}
+
+// Delete a subdirectory in the directory
+bool Directory::rmdir(std::string name, bool doRefresh /* = false */)
+{
+       std::string fullPath;
+
+       if (name.empty())
+               fullPath = path;
+       else
+               fullPath = path + OS_PATHSEP + name;
+
+#ifndef _WIN32
+       if (::rmdir(fullPath.c_str()) != 0)
+               return false;
+#else
+       if (_rmdir(fullPath.c_str()) != 0)
+               return false;
+#endif
+       if (doRefresh)
+               return refresh();
+       return true;
+}
+
+// Delete a file in the directory
+bool Directory::remove(std::string name)
+{
+       std::string fullPath = path + OS_PATHSEP + name;
+
+#ifndef _WIN32
+       return (!::remove(fullPath.c_str()) && refresh());
+#else
+       return (!_unlink(fullPath.c_str()) && refresh());
+#endif
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/Directory.h b/SoftHSMv2/src/lib/object_store/Directory.h
new file mode 100644 (file)
index 0000000..d7681a1
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Directory.h
+
+ Helper functions for accessing directories.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DIRECTORY_H
+#define _SOFTHSM_V2_DIRECTORY_H
+
+#include "config.h"
+#include "MutexFactory.h"
+#include <string>
+#include <vector>
+
+class Directory
+{
+public:
+       // Constructor
+       Directory(std::string inPath);
+
+       // Destructor
+       virtual ~Directory();
+
+       // Check if the directory is valid
+       bool isValid();
+
+       // Return a list of all files in a directory
+       std::vector<std::string> getFiles();
+
+       // Return a list of all subdirectories in a directory
+       std::vector<std::string> getSubDirs();
+
+       // Refresh the directory listing
+       bool refresh();
+
+       // Create a new subdirectory
+       bool mkdir(std::string name);
+
+       // Delete a subdirectory in the directory
+       bool rmdir(std::string name, bool doRefresh = false);
+
+       // Delete a file in the directory
+       bool remove(std::string name);
+
+private:
+       // The directory path
+       std::string path;
+
+       // The status
+       bool valid;
+
+       // All files in the directory
+       std::vector<std::string> files;
+
+       // All subdirectories in the directory
+       std::vector<std::string> subDirs;
+
+       // For thread safeness
+       Mutex* dirMutex;
+};
+
+#endif // !_SOFTHSM_V2_DIRECTORY_H
+
diff --git a/SoftHSMv2/src/lib/object_store/File.cpp b/SoftHSMv2/src/lib/object_store/File.cpp
new file mode 100644 (file)
index 0000000..2af8ea9
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ * 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 vector of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this vector 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.
+ */
+
+/*****************************************************************************
+ File.h
+
+ This class wraps standard C file I/O in a convenient way for the object store
+ *****************************************************************************/
+
+#include "config.h"
+#include "File.h"
+#include "log.h"
+#include <string>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <sys/file.h>
+#include <unistd.h>
+#else
+#include <io.h>
+#define F_SETLK                12
+#define F_SETLKW       13
+#define F_RDLCK                1
+#define F_UNLCK                2
+#define F_WRLCK                3
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+enum AttributeKind {
+       akUnknown,
+       akBoolean,
+       akInteger,
+       akBinary,
+       akAttrMap,
+       akMechSet
+};
+
+// Constructor
+//
+// N.B.: the create flag only has a function when a file is opened read/write
+// N.B.: the truncate flag only has a function when the create one is true
+File::File(std::string inPath, bool forRead /* = true */, bool forWrite /* = false */, bool create /* = false */, bool truncate /* = true */)
+{
+       stream = NULL;
+
+       isReadable = forRead;
+       isWritable = forWrite;
+       locked = false;
+
+       path = inPath;
+       valid = false;
+
+       if (forRead || forWrite)
+       {
+               std::string fileMode = "";
+               int flags, fd;
+
+#ifndef _WIN32
+               flags = 0;
+               if (forRead && !forWrite) flags |= O_RDONLY;
+               if (!forRead && forWrite) flags |= O_WRONLY | O_CREAT | O_TRUNC;
+               if (forRead && forWrite) flags |= O_RDWR;
+               if (forRead && forWrite && create) flags |= O_CREAT;
+               if (forRead && forWrite && create && truncate) flags |= O_TRUNC;
+               // Open the file
+               fd = open(path.c_str(), flags, 0600);
+               if (fd == -1)
+               {
+                       ERROR_MSG("Could not open the file (%s): %s", strerror(errno), path.c_str());
+                       valid = false;
+                       return;
+               }
+
+               if (forRead && !forWrite) fileMode = "r";
+               if (!forRead && forWrite) fileMode = "w";
+               if (forRead && forWrite && !create) fileMode = "r+";
+               if (forRead && forWrite && create) fileMode = "w+";
+               // Open the stream
+               valid = ((stream = fdopen(fd, fileMode.c_str())) != NULL);
+#else
+               flags = _O_BINARY;
+               if (forRead && !forWrite) flags |= _O_RDONLY;
+               if (!forRead && forWrite) flags |= _O_WRONLY | _O_CREAT | _O_TRUNC;
+               if (forRead && forWrite) flags |= _O_RDWR;
+               if (forRead && forWrite && create) flags |= _O_CREAT;
+               if (forRead && forWrite && create && truncate) flags |= _O_TRUNC;
+               // Open the file
+               fd = _open(path.c_str(), flags, _S_IREAD | _S_IWRITE);
+               if (fd == -1)
+               {
+                       ERROR_MSG("Could not open the file (%s): %s", strerror(errno), path.c_str());
+                       valid = false;
+                       return;
+               }
+
+               if (forRead && !forWrite) fileMode = "rb";
+               if (!forRead && forWrite) fileMode = "wb";
+               if (forRead && forWrite && !create) fileMode = "rb+";
+               if (forRead && forWrite && create) fileMode = "wb+";
+               // Open the stream
+               valid = ((stream = _fdopen(fd, fileMode.c_str())) != NULL);
+#endif
+       }
+}
+
+// Destructor
+File::~File()
+{
+       if (locked)
+       {
+               unlock();
+       }
+
+       if (stream != NULL)
+       {
+               fclose(stream);
+       }
+}
+
+// Check if the file is valid
+bool File::isValid()
+{
+       return valid;
+}
+
+// Check if the file is readable
+bool File::isRead()
+{
+       return isReadable;
+}
+
+// Check if the file is writable
+bool File::isWrite()
+{
+       return isWritable;
+}
+
+// Check if the file is empty
+bool File::isEmpty()
+{
+#ifndef _WIN32
+       struct stat s;
+
+       if (fstat(fileno(stream), &s) != 0)
+       {
+               valid = false;
+
+               return false;
+       }
+
+       return (s.st_size == 0);
+#else
+       struct _stat s;
+
+       if (_fstat(_fileno(stream), &s) != 0)
+       {
+               valid = false;
+
+               return false;
+       }
+
+       return (s.st_size == 0);
+#endif
+}
+
+// Check if the end-of-file was reached
+bool File::isEOF()
+{
+       return valid && feof(stream);
+}
+
+// Read an unsigned long value; warning: not thread safe without locking!
+bool File::readULong(unsigned long& value)
+{
+       if (!valid) return false;
+
+       ByteString ulongVal;
+
+       ulongVal.resize(8);
+
+       if (fread(&ulongVal[0], 1, 8, stream) != 8)
+       {
+               return false;
+       }
+
+       value = ulongVal.long_val();
+
+       return true;
+}
+
+// Read a ByteString value; warning: not thread safe without locking!
+bool File::readByteString(ByteString& value)
+{
+       if (!valid) return false;
+
+       // Retrieve the length to read from the file
+       unsigned long len;
+
+       if (!readULong(len))
+       {
+               return false;
+       }
+
+       // Read the byte string from the file
+       value.resize(len);
+
+       if (len == 0)
+       {
+               return true;
+       }
+
+       if (fread(&value[0], 1, len, stream) != len)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Read a boolean value; warning: not thread safe without locking!
+bool File::readBool(bool& value)
+{
+       if (!valid) return false;
+
+       // Read the boolean from the file
+       unsigned char boolValue;
+
+       if (fread(&boolValue, 1, 1, stream) != 1)
+       {
+               return false;
+       }
+
+       value = boolValue ? true : false;
+
+       return true;
+}
+
+// Read a mechanism type set value; warning: not thread safe without locking!
+bool File::readMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& value)
+{
+       if (!valid) return false;
+
+       unsigned long count;
+       if (!readULong(count)) return false;
+
+       for (unsigned long i = 0; i < count; i++)
+       {
+               unsigned long mechType;
+               if (!readULong(mechType))
+               {
+                       return false;
+               }
+
+               value.insert((CK_MECHANISM_TYPE) mechType);
+       }
+
+       return true;
+}
+
+// Read an attribute map value; warning: not thread safe without locking!
+bool File::readAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value)
+{
+       if (!valid) return false;
+
+       // Retrieve the length to read from the file
+       unsigned long len;
+
+       if (!readULong(len))
+       {
+               return false;
+       }
+
+       while (len != 0)
+       {
+               unsigned long attrType;
+               if (!readULong(attrType))
+               {
+                       return false;
+               }
+               if (8 > len)
+               {
+                       return false;
+               }
+               len -= 8;
+
+               unsigned long attrKind;
+               if (!readULong(attrKind))
+               {
+                       return false;
+               }
+               if (8 > len)
+               {
+                       return false;
+               }
+               len -= 8;
+
+               switch (attrKind)
+               {
+                       case akBoolean:
+                       {
+                               bool val;
+                               if (!readBool(val))
+                               {
+                                       return false;
+                               }
+                               if (1 > len)
+                               {
+                                       return false;
+                               }
+                               len -= 1;
+
+                               value.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, val));
+                       }
+                       break;
+
+                       case akInteger:
+                       {
+                               unsigned long val;
+                               if (!readULong(val))
+                               {
+                                       return false;
+                               }
+                               if (8 > len)
+                               {
+                                       return false;
+                               }
+                               len -= 8;
+
+                               value.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, val));
+                       }
+                       break;
+
+                       case akBinary:
+                       {
+                               ByteString val;
+                               if (!readByteString(val))
+                               {
+                                       return false;
+                               }
+                               if (8 + val.size() > len)
+                               {
+                                       return false;
+                               }
+                               len -= 8 + val.size();
+
+                               value.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, val));
+                       }
+                       break;
+
+                       case akMechSet:
+                       {
+                               std::set<CK_MECHANISM_TYPE> val;
+                               if (!readMechanismTypeSet(val))
+                               {
+                                       return false;
+                               }
+                               if (8 + val.size() * 8 > len)
+                               {
+                                       return false;
+                               }
+                               len -= 8 + val.size() * 8;
+
+                               value.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, val));
+                       }
+                       break;
+
+                       default:
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+// Read a string value; warning: not thread safe without locking!
+bool File::readString(std::string& value)
+{
+       if (!valid) return false;
+
+       // Retrieve the length to read from the file
+       unsigned long len;
+
+       if (!readULong(len))
+       {
+               return false;
+       }
+
+       // Read the string from the file
+       value.resize(len);
+
+       if (fread(&value[0], 1, len, stream) != len)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Write an unsigned long value; warning: not thread safe without locking!
+bool File::writeULong(const unsigned long value)
+{
+       if (!valid) return false;
+
+       ByteString toWrite(value);
+
+       // Write the value to the file
+       if (fwrite(toWrite.const_byte_str(), 1, toWrite.size(), stream) != toWrite.size())
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Write a ByteString value; warning: not thread safe without locking!
+bool File::writeByteString(const ByteString& value)
+{
+       if (!valid) return false;
+
+       ByteString toWrite = value.serialise();
+
+       // Write the value to the file
+       if (fwrite(toWrite.const_byte_str(), 1, toWrite.size(), stream) != toWrite.size())
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Write a string value; warning: not thread safe without locking!
+bool File::writeString(const std::string& value)
+{
+       if (!valid) return false;
+
+       ByteString toWrite((const unsigned long) value.size());
+
+       // Write the value to the file
+       if ((fwrite(toWrite.const_byte_str(), 1, toWrite.size(), stream) != toWrite.size()) ||
+           (fwrite(&value[0], 1, value.size(), stream) != value.size()))
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Write a mechanism type set value; warning: not thread safe without locking!
+bool File::writeMechanismTypeSet(const std::set<CK_MECHANISM_TYPE>& value)
+{
+       if (!valid) return false;
+
+       // write length
+       if (!writeULong(value.size()))
+       {
+               return false;
+       }
+
+       // write each value
+       for (std::set<CK_MECHANISM_TYPE>::const_iterator i = value.begin(); i != value.end(); ++i)
+       {
+               if (!writeULong(*i)) return false;
+       }
+
+       return true;
+}
+
+// Write an attribute map value; warning: not thread safe without locking!
+bool File::writeAttributeMap(const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value)
+{
+       if (!valid) return false;
+
+       // compute length
+       unsigned long len = 0;
+       for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = value.begin(); i != value.end(); ++i)
+       {
+               OSAttribute attr = i->second;
+               // count attribute type and kind
+               len += 8 + 8;
+
+               if (attr.isBooleanAttribute())
+               {
+                       len += 1;
+               }
+               else if (attr.isUnsignedLongAttribute())
+               {
+                       len += 8;
+               }
+               else if (attr.isByteStringAttribute())
+               {
+                       ByteString val = attr.getByteStringValue();
+                       len += 8 + val.size();
+               }
+               else if (attr.isMechanismTypeSetAttribute())
+               {
+                       std::set<CK_MECHANISM_TYPE> val = attr.getMechanismTypeSetValue();
+                       len += 8 + val.size() * 8;
+               }
+               else
+               {
+                       return false;
+               }
+       }
+
+       // write length
+       if (!writeULong(len))
+       {
+               return false;
+       }
+
+       // write each attribute
+       for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = value.begin(); i != value.end(); ++i)
+       {
+               OSAttribute attr = i->second;
+               unsigned long attrType = (unsigned long) i->first;
+               if (!writeULong(attrType))
+               {
+                       return false;
+               }
+
+               if (attr.isBooleanAttribute())
+               {
+                       unsigned long attrKind = akBoolean;
+                       if (!writeULong(attrKind))
+                       {
+                               return false;
+                       }
+
+                       bool val = attr.getBooleanValue();
+                       if (!writeBool(val))
+                       {
+                               return false;
+                       }
+               }
+               else if (attr.isUnsignedLongAttribute())
+               {
+                       unsigned long attrKind = akInteger;
+                       if (!writeULong(attrKind))
+                       {
+                               return false;
+                       }
+
+                       unsigned long val = attr.getUnsignedLongValue();
+                       if (!writeULong(val))
+                       {
+                               return false;
+                       }
+               }
+               else if (attr.isByteStringAttribute())
+               {
+                       unsigned long attrKind = akBinary;
+                       if (!writeULong(attrKind))
+                       {
+                               return false;
+                       }
+
+                       ByteString val = attr.getByteStringValue();
+                       if (!writeByteString(val))
+                       {
+                               return false;
+                       }
+               }
+               else if (attr.isMechanismTypeSetAttribute())
+               {
+                       unsigned long attrKind = akMechSet;
+                       if (!writeULong(attrKind))
+                       {
+                               return false;
+                       }
+
+                       std::set<CK_MECHANISM_TYPE> val = attr.getMechanismTypeSetValue();
+                       if (!writeMechanismTypeSet(val))
+                       {
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+// Write a boolean value; warning: not thread safe without locking!
+bool File::writeBool(const bool value)
+{
+       if (!valid) return false;
+
+       unsigned char toWrite = value ? 0xFF : 0x00;
+
+       // Write the value to the file
+       if (fwrite(&toWrite, 1, 1, stream) != 1)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// Rewind the file
+bool File::rewind()
+{
+       if (!valid) return false;
+
+       ::rewind(stream);
+
+       return true;
+}
+
+// Truncate the file
+bool File::truncate()
+{
+       if (!valid) return false;
+
+#ifndef _WIN32
+       return (::ftruncate(fileno(stream), 0) == 0);
+#else
+       return (_chsize(_fileno(stream), 0) == 0);
+#endif
+}
+
+// Seek to the specified position relative to the start of the file; if no
+// argument is specified this operation seeks to the end of the file
+bool File::seek(long offset /* = -1 */)
+{
+       if (offset == -1)
+       {
+               return valid && (valid = !fseek(stream, 0, SEEK_END));
+       }
+       else
+       {
+               return valid && (valid = !fseek(stream, offset, SEEK_SET));
+       }
+}
+
+// Lock the file
+bool File::lock(bool block /* = true */)
+{
+#ifndef _WIN32
+       struct flock fl;
+       fl.l_type = isWrite() ? F_WRLCK : F_RDLCK;
+       fl.l_whence = SEEK_SET;
+       fl.l_start = 0;
+       fl.l_len = 0;
+       fl.l_pid = 0;
+
+       if (locked || !valid) return false;
+
+       if (fcntl(fileno(stream), block ? F_SETLKW : F_SETLK, &fl) != 0)
+       {
+               ERROR_MSG("Could not lock the file: %s", strerror(errno));
+               return false;
+       }
+#else
+       HANDLE hFile;
+       DWORD flags = 0;
+       OVERLAPPED o;
+
+       if (isWrite()) flags |= LOCKFILE_EXCLUSIVE_LOCK;
+       if (!block) flags |= LOCKFILE_FAIL_IMMEDIATELY;
+
+       if (locked || !valid) return false;
+
+       hFile = (HANDLE) _get_osfhandle(_fileno(stream));
+       if (hFile == INVALID_HANDLE_VALUE)
+       {
+               ERROR_MSG("Invalid handle");
+               return false;
+       }
+
+       memset(&o, 0, sizeof(o));
+       if (!LockFileEx(hFile, flags, 0, 1, 0, &o))
+       {
+               DWORD rv = GetLastError();
+
+               ERROR_MSG("Could not lock the file: 0x%08x", rv);
+               return false;
+       }
+#endif
+
+       locked = true;
+
+       return true;
+}
+
+// Unlock the file
+bool File::unlock()
+{
+#ifndef _WIN32
+       struct flock fl;
+       fl.l_type = F_UNLCK;
+       fl.l_whence = SEEK_SET;
+       fl.l_start = 0;
+       fl.l_len = 0;
+       fl.l_pid = 0;
+
+       if (!locked || !valid) return false;
+
+       if (fcntl(fileno(stream), F_SETLK, &fl) != 0)
+       {
+               valid = false;
+
+               ERROR_MSG("Could not unlock the file: %s", strerror(errno));
+               return false;
+       }
+#else
+       HANDLE hFile;
+       OVERLAPPED o;
+
+       if (!locked || !valid) return false;
+
+       hFile = (HANDLE) _get_osfhandle(_fileno(stream));
+       if (hFile == INVALID_HANDLE_VALUE)
+       {
+               ERROR_MSG("Invalid handle");
+               return false;
+       }
+
+       memset(&o, 0, sizeof(o));
+       if (!UnlockFileEx(hFile, 0, 1, 0, &o))
+       {
+               DWORD rv = GetLastError();
+
+               valid = false;
+
+               ERROR_MSG("Could not unlock the file: 0x%08x", rv);
+               return  false;
+       }
+#endif
+                       
+
+       locked = false;
+
+       return valid;
+}
+
+// Flush the buffered stream to background storage
+bool File::flush()
+{
+       return valid && !fflush(stream);
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/File.h b/SoftHSMv2/src/lib/object_store/File.h
new file mode 100644 (file)
index 0000000..da27af6
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ File.h
+
+ This class wraps standard C file I/O in a convenient way for the object store
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_FILE_H
+#define _SOFTHSM_V2_FILE_H
+
+#include "config.h"
+#include "OSAttribute.h"
+#include <stdio.h>
+#include <string>
+
+class File
+{
+public:
+       // Constructor
+       File(std::string inPath, bool forRead = true, bool forWrite = false, bool create = false, bool truncate = true);
+
+       // Destructor
+       virtual ~File();
+
+       // Check if the file is valid
+       bool isValid();
+
+       // Check if the file is readable
+       bool isRead();
+
+       // Check if the file is writable
+       bool isWrite();
+
+       // Check if the file is empty
+       bool isEmpty();
+
+       // Check if the end-of-file was reached
+       bool isEOF();
+
+       // Read an unsigned long value; warning: not thread safe without locking!
+       bool readULong(unsigned long& value);
+
+       // Read a ByteString value; warning: not thread safe without locking!
+       bool readByteString(ByteString& value);
+
+       // Read a string value; warning: not thread safe without locking!
+       bool readString(std::string& value);
+
+       // Read a boolean value; warning: not thread safe without locking!
+       bool readBool(bool& value);
+
+       // Read a mechanism type set value; warning: not thread safe without locking!
+       bool readMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& value);
+
+       // Read an array value; warning: not thread safe without locking!
+       bool readAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value);
+
+       // Write an unsigned long value; warning: not thread safe without locking!
+       bool writeULong(const unsigned long value);
+
+       // Write a ByteString value; warning: not thread safe without locking!
+       bool writeByteString(const ByteString& value);
+
+       // Write a string value; warning: not thread safe without locking!
+       bool writeString(const std::string& value);
+
+       // Write a boolean value; warning: not thread safe without locking!
+       bool writeBool(const bool value);
+
+       // Write a mechanism type set value; warning: not thread safe without locking!
+       bool writeMechanismTypeSet(const std::set<CK_MECHANISM_TYPE>& value);
+
+       // Write an attribute map value; warning: not thread safe without locking!
+       bool writeAttributeMap(const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value);
+
+       // Rewind the file
+       bool rewind();
+
+       // Truncate the file
+       bool truncate();
+
+       // Seek to the specified position relative to the start of the file; if no
+       // argument is specified this operation seeks to the end of the file
+       bool seek(long offset = -1);
+
+       // Lock the file
+       bool lock(bool block = true);
+
+       // Unlock the file
+       bool unlock();
+
+       // Flush the buffered stream to background storage
+       bool flush();
+
+private:
+       // The file path
+       std::string path;
+
+       // The status
+       bool valid;
+       bool locked;
+
+       // Read, write or both?
+       bool isReadable, isWritable;
+
+       // The FILE stream
+       FILE* stream;
+};
+
+#endif // !_SOFTHSM_V2_FILE_H
+
diff --git a/SoftHSMv2/src/lib/object_store/FindOperation.cpp b/SoftHSMv2/src/lib/object_store/FindOperation.cpp
new file mode 100644 (file)
index 0000000..db6dda1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ FindOperation.cpp
+
+ This class represents the find operation that can be used to collect
+ objects that match the attributes contained in a given template.
+ *****************************************************************************/
+
+#include "config.h"
+#include "FindOperation.h"
+
+FindOperation::FindOperation()
+{
+}
+
+FindOperation *FindOperation::create()
+{
+    return new FindOperation();
+}
+
+void FindOperation::recycle()
+{
+    delete this;
+}
+
+void FindOperation::setHandles(const std::set<CK_OBJECT_HANDLE> &handles)
+{
+    _handles = handles;
+}
+
+CK_ULONG FindOperation::retrieveHandles(CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulCount)
+{
+    CK_ULONG ulReturn = 0;
+    std::set<CK_OBJECT_HANDLE>::const_iterator it;
+    for (it=_handles.begin(); it != _handles.end(); ++it) {
+        if (ulReturn >= ulCount) break;
+
+        phObject[ulReturn++] = *it;
+    }
+    return ulReturn;
+}
+
+CK_ULONG FindOperation::eraseHandles(CK_ULONG ulIndex, CK_ULONG ulCount)
+{
+    std::set<CK_OBJECT_HANDLE>::const_iterator it;
+    for (it=_handles.begin(); it != _handles.end() && ulIndex != 0; --ulIndex) {
+        ++it;
+    }
+
+    CK_ULONG ulReturn = 0;
+    for ( ; it != _handles.end() && ulReturn < ulCount; ++ulReturn) {
+        _handles.erase(it++);
+    }
+    return ulReturn;
+}
diff --git a/SoftHSMv2/src/lib/object_store/FindOperation.h b/SoftHSMv2/src/lib/object_store/FindOperation.h
new file mode 100644 (file)
index 0000000..ea6410a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*****************************************************************************
+ FindOperation.h
+
+ This class represents the find operation that can be used to collect
+ objects that match the attributes contained in a given template.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_FINDOPERATION_H
+#define _SOFTHSM_V2_FINDOPERATION_H
+
+#include "config.h"
+
+#include <set>
+#include "OSObject.h"
+
+class FindOperation
+{
+public:
+    // Factory method creates a new find operation
+    static FindOperation* create();
+
+    // Hand this operation back to the factory for recycling.
+    void recycle();
+
+    // Add the objects from thet set that match the attributes in the given template to the find operation.
+    void setHandles(const std::set<CK_OBJECT_HANDLE> &handles);
+
+    // Retrieve handles
+    CK_ULONG retrieveHandles(CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulCount);
+
+    // Erase handles from the handles set.
+    CK_ULONG eraseHandles(CK_ULONG ulIndex, CK_ULONG ulCount);
+
+protected:
+    // Use a protected constructor to force creation via factory method.
+    FindOperation();
+
+    std::set<CK_OBJECT_HANDLE> _handles;
+};
+
+#endif // _SOFTHSM_V2_FINDOPERATION_H
diff --git a/SoftHSMv2/src/lib/object_store/Generation.cpp b/SoftHSMv2/src/lib/object_store/Generation.cpp
new file mode 100644 (file)
index 0000000..196dac2
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ Generation.cpp
+
+ Helper for generation number handling.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "Generation.h"
+
+// Factory
+Generation* Generation::create(const std::string path, bool isToken /* = false */)
+{
+       Generation* gen = new Generation(path, isToken);
+       if ((gen != NULL) && isToken && (gen->genMutex == NULL))
+       {
+               delete gen;
+
+               return NULL;
+       }
+       return gen;
+}
+
+// Destructor
+Generation::~Generation()
+{
+       if (isToken)
+       {
+               MutexFactory::i()->recycleMutex(genMutex);
+       }
+}
+
+// Synchronize from locked disk file
+bool Generation::sync(File &objectFile)
+{
+       if (isToken)
+       {
+               ERROR_MSG("Generation sync() called for a token");
+
+               return false;
+       }
+
+       unsigned long onDisk;
+
+       if (!objectFile.readULong(onDisk))
+       {
+               if (objectFile.isEOF())
+               {
+                       onDisk = 0;
+               }
+               else
+               {
+                       return false;
+               }
+       }
+
+       currentValue = onDisk;
+
+       return objectFile.seek(0L);
+}
+
+// Check if the target was updated
+bool Generation::wasUpdated()
+{
+       if (isToken)
+       {
+               MutexLocker lock(genMutex);
+
+               File genFile(path);
+
+               if (!genFile.isValid())
+               {
+                       return true;
+               }
+
+               genFile.lock();
+
+               unsigned long onDisk;
+
+               if (!genFile.readULong(onDisk))
+               {
+                       return true;
+               }
+
+               if (onDisk != currentValue)
+               {
+                       currentValue = onDisk;
+                       return true;
+               }
+
+               return false;
+       }
+       else
+       {
+               File objectFile(path);
+
+               if (!objectFile.isValid())
+               {
+                       return true;
+               }
+
+               objectFile.lock();
+
+               unsigned long onDisk;
+
+               if (!objectFile.readULong(onDisk))
+               {
+                       return true;
+               }
+
+               return (onDisk != currentValue);
+       }
+}
+
+// Update
+void Generation::update()
+{
+       pendingUpdate = true;
+}
+
+// Commit
+void Generation::commit()
+{
+       if (isToken)
+       {
+               MutexLocker lock(genMutex);
+
+               File genFile(path, true, true, true, false);
+
+               if (!genFile.isValid())
+               {
+                       return;
+               }
+
+               genFile.lock();
+
+               if (genFile.isEmpty())
+               {
+                       currentValue++;
+
+                       if (currentValue == 0)
+                       {
+                               currentValue++;
+                       }
+
+                       pendingUpdate = false;
+
+                       (void) genFile.writeULong(currentValue);
+
+                       genFile.unlock();
+
+                       return;
+               }
+
+               unsigned long onDisk;
+
+               bool bOK = true;
+
+               bOK = bOK && genFile.readULong(onDisk);
+               bOK = bOK && genFile.seek(0L);
+
+               if (pendingUpdate)
+               {
+                       onDisk++;
+
+                       if (onDisk == 0)
+                       {
+                               onDisk++;
+                       }
+               }
+
+               bOK = bOK && genFile.writeULong(onDisk);
+
+               if (bOK)
+               {
+                       currentValue = onDisk;
+
+                       pendingUpdate = false;
+               }
+
+               genFile.unlock();
+       }
+}
+
+// Set the current value when read from disk
+void Generation::set(unsigned long onDisk)
+{
+       currentValue = onDisk;
+}
+
+// Return new value
+unsigned long Generation::get()
+{
+       pendingUpdate = false;
+
+       currentValue++;
+
+       if (currentValue == 0)
+       {
+               currentValue = 1;
+       }
+
+       return currentValue;
+}
+
+// Rollback (called when the new value failed to be written)
+void Generation::rollback()
+{
+       pendingUpdate = true;
+
+       if (currentValue != 1)
+       {
+               currentValue--;
+       }
+}
+
+// Constructor
+Generation::Generation(const std::string inPath, bool inIsToken)
+{
+       path = inPath;
+       isToken = inIsToken;
+       pendingUpdate = false;
+       currentValue = 0;
+       genMutex = NULL;
+
+       if (isToken)
+       {
+               genMutex = MutexFactory::i()->getMutex();
+
+               if (genMutex != NULL)
+               {
+                       commit();
+               }
+       }
+}
diff --git a/SoftHSMv2/src/lib/object_store/Generation.h b/SoftHSMv2/src/lib/object_store/Generation.h
new file mode 100644 (file)
index 0000000..106f34b
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ Generation.h
+
+ Helper for generation number handling.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_GENERATION_H
+#define _SOFTHSM_V2_GENERATION_H
+
+#include "config.h"
+#include <string>
+#include "File.h"
+#include "MutexFactory.h"
+
+class Generation
+{
+public:
+       // Factory
+       static Generation* create(const std::string inPath, bool inIsToken = false);
+
+       // Destructor
+       virtual ~Generation();
+
+       // Synchronize from locked disk file
+       bool sync(File &objectfile);
+
+       // Check if the target was updated
+       bool wasUpdated();
+
+       // Note pending update
+       void update();
+
+       // Commit (for the token case)
+       void commit();
+
+       // Set the current value when read from disk
+       void set(unsigned long onDisk);
+
+       // Return new value
+       unsigned long get();
+
+       // Rollback (called when the new value failed to be written)
+       void rollback();
+
+private:
+       // Constructor
+       Generation(const std::string path, bool isToken);
+
+       // The file path
+       std::string path;
+
+       // isToken
+       bool isToken;
+
+       // Pending update
+       bool pendingUpdate;
+
+       // Current value
+       unsigned long currentValue;
+
+       // For thread safeness
+       Mutex* genMutex;
+};
+
+#endif // !_SOFTHSM_V2_GENERATION_H
+
diff --git a/SoftHSMv2/src/lib/object_store/Makefile.am b/SoftHSMv2/src/lib/object_store/Makefile.am
new file mode 100644 (file)
index 0000000..d3e89d3
--- /dev/null
@@ -0,0 +1,34 @@
+MAINTAINERCLEANFILES =                         $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                          -I$(srcdir)/.. \
+                                       -I$(srcdir)/../common \
+                                       -I$(srcdir)/../crypto \
+                                       -I$(srcdir)/../data_mgr \
+                                       -I$(srcdir)/../pkcs11 \
+                                       @SQLITE3_INCLUDES@
+
+noinst_LTLIBRARIES =                   libsofthsm_objectstore.la
+libsofthsm_objectstore_la_SOURCES =    ObjectStore.cpp \
+                                       UUID.cpp \
+                                       Directory.cpp \
+                                       File.cpp \
+                                       Generation.cpp \
+                                       OSAttribute.cpp \
+                                       OSToken.cpp \
+                                       ObjectFile.cpp \
+                                       SessionObject.cpp \
+                                       SessionObjectStore.cpp \
+                                       FindOperation.cpp \
+                                       ObjectStoreToken.cpp
+
+if BUILD_OBJECTSTORE_BACKEND_DB
+libsofthsm_objectstore_la_SOURCES +=   DB.cpp \
+                                       DBObject.cpp \
+                                       DBToken.cpp
+endif
+
+libsofthsm_objectstore_la_LDFLAGS =    @SQLITE3_LIBS@
+
+SUBDIRS =                              test
+
+EXTRA_DIST =                           $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/object_store/OSAttribute.cpp b/SoftHSMv2/src/lib/object_store/OSAttribute.cpp
new file mode 100644 (file)
index 0000000..9d7e5a3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSAttribute.cpp
+
+ This class represents the object store view on an object's attribute
+ *****************************************************************************/
+
+#include "config.h"
+#include "OSAttribute.h"
+
+// Copy constructor
+OSAttribute::OSAttribute(const OSAttribute& in)
+{
+       attributeType = in.attributeType;
+       boolValue = in.boolValue;
+       ulongValue = in.ulongValue;
+       byteStrValue = in.byteStrValue;
+       mechSetValue = in.mechSetValue;
+       attrMapValue = in.attrMapValue;
+}
+
+// Constructor for a boolean type attribute
+OSAttribute::OSAttribute(const bool value)
+{
+       boolValue = value;
+       attributeType = BOOL;
+
+       ulongValue = 0;
+}
+
+// Constructor for an unsigned long type attribute
+OSAttribute::OSAttribute(const unsigned long value)
+{
+       ulongValue = value;
+       attributeType = ULONG;
+
+       boolValue = false;
+}
+
+// Constructor for a byte string type attribute
+OSAttribute::OSAttribute(const ByteString& value)
+{
+       byteStrValue = value;
+       attributeType = BYTESTR;
+
+       boolValue = false;
+       ulongValue = 0;
+}
+
+// Constructor for a mechanism type set attribute
+OSAttribute::OSAttribute(const std::set<CK_MECHANISM_TYPE>& value)
+{
+       mechSetValue = value;
+       attributeType = MECHSET;
+
+       boolValue = false;
+       ulongValue = 0;
+}
+
+// Constructor for an attribute map type attribute
+OSAttribute::OSAttribute(const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value)
+{
+       attrMapValue = value;
+       attributeType = ATTRMAP;
+
+       boolValue = false;
+       ulongValue = 0;
+}
+
+// Check the attribute type
+bool OSAttribute::isBooleanAttribute() const
+{
+       return (attributeType == BOOL);
+}
+
+bool OSAttribute::isUnsignedLongAttribute() const
+{
+       return (attributeType == ULONG);
+}
+
+bool OSAttribute::isByteStringAttribute() const
+{
+       return (attributeType == BYTESTR);
+}
+
+bool OSAttribute::isMechanismTypeSetAttribute() const
+{
+       return (attributeType == MECHSET);
+}
+
+bool OSAttribute::isAttributeMapAttribute() const
+{
+       return (attributeType == ATTRMAP);
+}
+
+// Retrieve the attribute value
+bool OSAttribute::getBooleanValue() const
+{
+       return boolValue;
+}
+
+unsigned long OSAttribute::getUnsignedLongValue() const
+{
+       return ulongValue;
+}
+
+const ByteString& OSAttribute::getByteStringValue() const
+{
+       return byteStrValue;
+}
+
+const std::set<CK_MECHANISM_TYPE>& OSAttribute::getMechanismTypeSetValue() const
+{
+       return mechSetValue;
+}
+
+const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& OSAttribute::getAttributeMapValue() const
+{
+       return attrMapValue;
+}
+
+// Helper for template (aka array) matching
+
+bool OSAttribute::peekValue(ByteString& value) const
+{
+       size_t counter = 0;
+       CK_MECHANISM_TYPE mech;
+
+       switch (attributeType)
+       {
+               case BOOL:
+                       value.resize(sizeof(boolValue));
+                       memcpy(&value[0], &boolValue, value.size());
+                       return true;
+
+               case ULONG:
+                       value.resize(sizeof(ulongValue));
+                       memcpy(&value[0], &ulongValue, value.size());
+                       return true;
+
+               case BYTESTR:
+                       value.resize(byteStrValue.size());
+                       memcpy(&value[0], byteStrValue.const_byte_str(), value.size());
+                       return true;
+
+               case MECHSET:
+                       value.resize(mechSetValue.size() * sizeof(mech));
+                       for (std::set<CK_MECHANISM_TYPE>::const_iterator i = mechSetValue.begin(); i != mechSetValue.end(); ++i)
+                       {
+                               mech = *i;
+                               memcpy(&value[0] + counter * sizeof(mech), &mech, sizeof(mech));
+                               counter++;
+                       }
+                       return true;
+
+               case ATTRMAP:
+                       return false;
+
+               default:
+                       return false;
+       }
+}
diff --git a/SoftHSMv2/src/lib/object_store/OSAttribute.h b/SoftHSMv2/src/lib/object_store/OSAttribute.h
new file mode 100644 (file)
index 0000000..303a5b9
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSAttribute.h
+
+ This class represents the object store view on an object's attribute
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSATTRIBUTE_H
+#define _SOFTHSM_V2_OSATTRIBUTE_H
+
+#include "config.h"
+#include "ByteString.h"
+#include <map>
+#include <set>
+
+class OSAttribute
+{
+public:
+       // Copy constructor
+       OSAttribute(const OSAttribute& in);
+
+       // Constructor for a boolean type attribute
+       OSAttribute(const bool value);
+
+       // Constructor for an unsigned long type attribute
+       OSAttribute(const unsigned long value);
+
+       // Constructor for a byte string type attribute
+       OSAttribute(const ByteString& value);
+
+       // Constructor for a mechanism type set type attribute
+       OSAttribute(const std::set<CK_MECHANISM_TYPE>& value);
+
+       // Constructor for an attribute map type attribute
+       OSAttribute(const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value);
+
+       // Destructor
+       virtual ~OSAttribute() { }
+
+       // Check the attribute type
+       bool isBooleanAttribute() const;
+       bool isUnsignedLongAttribute() const;
+       bool isByteStringAttribute() const;
+       bool isMechanismTypeSetAttribute() const;
+       bool isAttributeMapAttribute() const;
+
+       // Retrieve the attribute value
+       bool getBooleanValue() const;
+       unsigned long getUnsignedLongValue() const;
+       const ByteString& getByteStringValue() const;
+       const std::set<CK_MECHANISM_TYPE>& getMechanismTypeSetValue() const;
+       const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& getAttributeMapValue() const;
+
+       // Helper for template (aka array) matching
+       bool peekValue(ByteString& value) const;
+
+private:
+       // The attribute type
+       enum
+       {
+               BOOL,
+               ULONG,
+               BYTESTR,
+               MECHSET,
+               ATTRMAP
+       }
+       attributeType;
+
+       // The attribute value
+       bool boolValue;
+       unsigned long ulongValue;
+       ByteString byteStrValue;
+       std::set<CK_MECHANISM_TYPE> mechSetValue;
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> attrMapValue;
+};
+
+#endif // !_SOFTHSM_V2_OSATTRIBUTE_H
+
diff --git a/SoftHSMv2/src/lib/object_store/OSAttributes.h b/SoftHSMv2/src/lib/object_store/OSAttributes.h
new file mode 100644 (file)
index 0000000..dfc5869
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSAttributes.h
+
+ Specifies vendor defined attributes for use in internal object store files
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSATTRIBUTES_H
+#define _SOFTHSM_V2_OSATTRIBUTES_H
+
+#include "config.h"
+#include "cryptoki.h"
+
+// Define vendor tag; presumably the one below is reasonably unique
+#define CKA_VENDOR_SOFTHSM     (CKA_VENDOR_DEFINED + 0x5348) // 'SH'
+
+// Vendor defined attribute types for the token file
+#define CKA_OS_TOKENLABEL      (CKA_VENDOR_SOFTHSM + 1)
+#define CKA_OS_TOKENSERIAL     (CKA_VENDOR_SOFTHSM + 2)
+#define CKA_OS_TOKENFLAGS      (CKA_VENDOR_SOFTHSM + 3)
+#define CKA_OS_SOPIN           (CKA_VENDOR_SOFTHSM + 4)
+#define CKA_OS_USERPIN         (CKA_VENDOR_SOFTHSM + 5)
+
+#endif // !_SOFTHSM_V2_OSATTRIBUTES_H
+
diff --git a/SoftHSMv2/src/lib/object_store/OSObject.h b/SoftHSMv2/src/lib/object_store/OSObject.h
new file mode 100644 (file)
index 0000000..6efaa6d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSObject.h
+
+ This file contains the abstract interface for ObjectStore objects. It is
+ implemented by persistent objects in the form of the ObjectFile class and
+ by session objects in the form of the SessionObject class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSOBJECT_H
+#define _SOFTHSM_V2_OSOBJECT_H
+
+#include "config.h"
+#include "OSAttribute.h"
+#include "cryptoki.h"
+
+class OSObject
+{
+public:
+       // Destructor
+       virtual ~OSObject() { }
+
+       // Check if the specified attribute exists
+       virtual bool attributeExists(CK_ATTRIBUTE_TYPE type) = 0;
+
+       // Retrieve the specified attribute
+       virtual OSAttribute getAttribute(CK_ATTRIBUTE_TYPE type) = 0;
+       virtual bool getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val) = 0;
+       virtual unsigned long getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val) = 0;
+       virtual ByteString getByteStringValue(CK_ATTRIBUTE_TYPE type) = 0;
+
+       // Retrieve the next attribute type
+       virtual CK_ATTRIBUTE_TYPE nextAttributeType(CK_ATTRIBUTE_TYPE type) = 0;
+
+       // Set the specified attribute
+       virtual bool setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute) = 0;
+
+       // Delete the specified attribute
+       virtual bool deleteAttribute(CK_ATTRIBUTE_TYPE type) = 0;
+
+       // The validity state of the object
+       virtual bool isValid() = 0;
+
+       // Start an attribute set transaction; this method is used when - for
+       // example - a key is generated and all its attributes need to be
+       // persisted in one go.
+       //
+       // N.B.: Starting a transaction locks the object!
+       //
+       // Function returns false in case a transaction is already in progress
+       enum Access {
+               ReadOnly,
+               ReadWrite
+       };
+       virtual bool startTransaction(Access access = ReadWrite) = 0;
+
+       // Commit an attribute transaction; returns false if no transaction is in progress
+       virtual bool commitTransaction() = 0;
+
+       // Abort an attribute transaction; loads back the previous version of the object from disk;
+       // returns false if no transaction was in progress
+       virtual bool abortTransaction() = 0;
+
+       // Destroys the object (warning, any pointers to the object are no longer
+       // valid after this call because delete is called!)
+       virtual bool destroyObject() = 0;
+};
+
+#endif // !_SOFTHSM_V2_OSOBJECT_H
+
diff --git a/SoftHSMv2/src/lib/object_store/OSPathSep.h b/SoftHSMv2/src/lib/object_store/OSPathSep.h
new file mode 100644 (file)
index 0000000..f714d24
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSPathSep.h
+
+ Determine the OS specific path separator
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSPATHSEP_H
+#define _SOFTHSM_V2_OSPATHSEP_H
+
+#include "config.h"
+
+#ifdef _WIN32
+#define OS_PATHSEP "\\"
+#else
+#define OS_PATHSEP "/"
+#endif
+
+#endif // !_SOFTHSM_V2_OSPATHSEP_H
+
diff --git a/SoftHSMv2/src/lib/object_store/OSToken.cpp b/SoftHSMv2/src/lib/object_store/OSToken.cpp
new file mode 100644 (file)
index 0000000..13b1eaa
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSToken.cpp
+
+ The token class; a token is stored in a directory containing several files.
+ Each object is stored in a separate file and a token object is present that
+ has the token specific attributes
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSAttributes.h"
+#include "OSAttribute.h"
+#include "ObjectFile.h"
+#include "Directory.h"
+#include "Generation.h"
+#include "UUID.h"
+#include "cryptoki.h"
+#include "OSToken.h"
+#include "OSPathSep.h"
+#include <vector>
+#include <string>
+#include <set>
+#include <map>
+#include <list>
+#include <stdio.h>
+
+// Constructor
+OSToken::OSToken(const std::string inTokenPath)
+{
+       tokenPath = inTokenPath;
+
+       tokenDir = new Directory(tokenPath);
+       gen = Generation::create(tokenPath + OS_PATHSEP + "generation", true);
+       tokenObject = new ObjectFile(this, tokenPath + OS_PATHSEP + "token.object", tokenPath + OS_PATHSEP + "token.lock");
+       tokenMutex = MutexFactory::i()->getMutex();
+       valid = (gen != NULL) && (tokenMutex != NULL) && tokenDir->isValid() && tokenObject->valid;
+
+       DEBUG_MSG("Opened token %s", tokenPath.c_str());
+
+       index(true);
+}
+
+// Create a new token
+/*static*/ OSToken* OSToken::createToken(const std::string basePath, const std::string tokenDir, const ByteString& label, const ByteString& serial)
+{
+       Directory baseDir(basePath);
+
+       if (!baseDir.isValid())
+       {
+               ERROR_MSG("Could not create the Directory object");
+               return NULL;
+       }
+
+       // Create the token directory
+       if (!baseDir.mkdir(tokenDir))
+       {
+               // Error msg is generated by mkdir
+               return NULL;
+       }
+
+       // Create the token object
+       ObjectFile tokenObject(NULL, basePath + OS_PATHSEP + tokenDir + OS_PATHSEP + "token.object", basePath + OS_PATHSEP + tokenDir + OS_PATHSEP + "token.lock", true);
+
+       if (!tokenObject.valid)
+       {
+               std::string tokenPath = basePath + OS_PATHSEP + tokenDir + OS_PATHSEP + "token.[object|lock]";
+               ERROR_MSG("Failed to create the token object: %s", tokenPath.c_str());
+
+               baseDir.rmdir(tokenDir);
+
+               return NULL;
+       }
+
+       // Set the initial attributes
+       CK_ULONG flags =
+               CKF_RNG |
+               CKF_LOGIN_REQUIRED | // FIXME: check
+               CKF_RESTORE_KEY_NOT_NEEDED |
+               CKF_TOKEN_INITIALIZED |
+               CKF_SO_PIN_LOCKED |
+               CKF_SO_PIN_TO_BE_CHANGED;
+
+       OSAttribute tokenLabel(label);
+       OSAttribute tokenSerial(serial);
+       OSAttribute tokenFlags(flags);
+
+       if (!tokenObject.setAttribute(CKA_OS_TOKENLABEL, tokenLabel) ||
+           !tokenObject.setAttribute(CKA_OS_TOKENSERIAL, tokenSerial) ||
+           !tokenObject.setAttribute(CKA_OS_TOKENFLAGS, tokenFlags))
+       {
+               ERROR_MSG("Failed to set the token attributes");
+
+               baseDir.remove(tokenDir + OS_PATHSEP + "token.object");
+               baseDir.remove(tokenDir + OS_PATHSEP + "token.lock");
+               baseDir.rmdir(tokenDir);
+
+               return NULL;
+       }
+
+       DEBUG_MSG("Created new token %s", tokenDir.c_str());
+
+       return new OSToken(basePath + OS_PATHSEP + tokenDir);
+}
+
+// Access an existing token
+/*static*/ OSToken *OSToken::accessToken(const std::string &basePath, const std::string &tokenDir)
+{
+       return new OSToken(basePath + OS_PATHSEP + tokenDir);
+}
+
+// Destructor
+OSToken::~OSToken()
+{
+       // Clean up
+       std::set<OSObject*> cleanUp = allObjects;
+       allObjects.clear();
+
+       for (std::set<OSObject*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               delete *i;
+       }
+
+       delete tokenDir;
+       if (gen != NULL) delete gen;
+       MutexFactory::i()->recycleMutex(tokenMutex);
+       delete tokenObject;
+}
+
+// Set the SO PIN
+bool OSToken::setSOPIN(const ByteString& soPINBlob)
+{
+       if (!valid) return false;
+
+       OSAttribute soPIN(soPINBlob);
+
+       CK_ULONG flags;
+
+       if (tokenObject->setAttribute(CKA_OS_SOPIN, soPIN) &&
+           getTokenFlags(flags))
+       {
+               flags &= ~CKF_SO_PIN_COUNT_LOW;
+               flags &= ~CKF_SO_PIN_FINAL_TRY;
+               flags &= ~CKF_SO_PIN_LOCKED;
+               flags &= ~CKF_SO_PIN_TO_BE_CHANGED;
+
+               return setTokenFlags(flags);
+       }
+
+       return false;
+}
+
+// Get the SO PIN
+bool OSToken::getSOPIN(ByteString& soPINBlob)
+{
+       if (!valid || !tokenObject->isValid())
+       {
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_SOPIN))
+       {
+               soPINBlob = tokenObject->getAttribute(CKA_OS_SOPIN).getByteStringValue();
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+// Set the user PIN
+bool OSToken::setUserPIN(ByteString userPINBlob)
+{
+       if (!valid) return false;
+
+       OSAttribute userPIN(userPINBlob);
+
+       CK_ULONG flags;
+
+       if (tokenObject->setAttribute(CKA_OS_USERPIN, userPIN) &&
+           getTokenFlags(flags))
+       {
+               flags |= CKF_USER_PIN_INITIALIZED;
+               flags &= ~CKF_USER_PIN_COUNT_LOW;
+               flags &= ~CKF_USER_PIN_FINAL_TRY;
+               flags &= ~CKF_USER_PIN_LOCKED;
+               flags &= ~CKF_USER_PIN_TO_BE_CHANGED;
+
+               return setTokenFlags(flags);
+       }
+
+       return false;
+}
+
+// Get the user PIN
+bool OSToken::getUserPIN(ByteString& userPINBlob)
+{
+       if (!valid || !tokenObject->isValid())
+       {
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_USERPIN))
+       {
+               userPINBlob = tokenObject->getAttribute(CKA_OS_USERPIN).getByteStringValue();
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+// Retrieve the token label
+bool OSToken::getTokenLabel(ByteString& label)
+{
+       if (!valid || !tokenObject->isValid())
+       {
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_TOKENLABEL))
+       {
+               label = tokenObject->getAttribute(CKA_OS_TOKENLABEL).getByteStringValue();
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+// Retrieve the token serial
+bool OSToken::getTokenSerial(ByteString& serial)
+{
+       if (!valid || !tokenObject->isValid())
+       {
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_TOKENSERIAL))
+       {
+               serial = tokenObject->getAttribute(CKA_OS_TOKENSERIAL).getByteStringValue();
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+// Get the token flags
+bool OSToken::getTokenFlags(CK_ULONG& flags)
+{
+       if (!valid || !tokenObject->isValid())
+       {
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_TOKENFLAGS))
+       {
+               flags = tokenObject->getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue();
+
+               // Check if the user PIN is initialised
+               if (tokenObject->attributeExists(CKA_OS_USERPIN))
+               {
+                       flags |= CKF_USER_PIN_INITIALIZED;
+               }
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+// Set the token flags
+bool OSToken::setTokenFlags(const CK_ULONG flags)
+{
+       if (!valid) return false;
+
+       OSAttribute tokenFlags(flags);
+
+       return tokenObject->setAttribute(CKA_OS_TOKENFLAGS, tokenFlags);
+}
+
+// Retrieve objects
+std::set<OSObject*> OSToken::getObjects()
+{
+       index();
+
+       // Make sure that no other thread is in the process of changing
+       // the object list when we return it
+       MutexLocker lock(tokenMutex);
+
+       return objects;
+}
+
+void OSToken::getObjects(std::set<OSObject*> &inObjects)
+{
+       index();
+
+       // Make sure that no other thread is in the process of changing
+       // the object list when we return it
+       MutexLocker lock(tokenMutex);
+
+       inObjects.insert(objects.begin(),objects.end());
+}
+
+// Create a new object
+OSObject* OSToken::createObject()
+{
+       if (!valid) return NULL;
+
+       // Generate a name for the object
+       std::string objectUUID = UUID::newUUID();
+       std::string objectPath = tokenPath + OS_PATHSEP + objectUUID + ".object";
+       std::string lockPath = tokenPath + OS_PATHSEP + objectUUID + ".lock";
+
+       // Create the new object file
+       ObjectFile* newObject = new ObjectFile(this, objectPath, lockPath, true);
+
+       if (!newObject->valid)
+       {
+               ERROR_MSG("Failed to create new object %s", objectPath.c_str());
+
+               delete newObject;
+
+               return NULL;
+       }
+
+       // Now add it to the set of objects
+       MutexLocker lock(tokenMutex);
+
+       objects.insert(newObject);
+       allObjects.insert(newObject);
+       currentFiles.insert(newObject->getFilename());
+
+       DEBUG_MSG("(0x%08X) Created new object %s (0x%08X)", this, objectPath.c_str(), newObject);
+
+       gen->update();
+
+       gen->commit();
+
+       return newObject;
+}
+
+// Delete an object
+bool OSToken::deleteObject(OSObject* object)
+{
+       if (!valid) return false;
+
+       if (objects.find(object) == objects.end())
+       {
+               ERROR_MSG("Cannot delete non-existent object 0x%08X", object);
+
+               return false;
+       }
+
+       MutexLocker lock(tokenMutex);
+
+       ObjectFile* fileObject = dynamic_cast<ObjectFile*>(object);
+       if (fileObject == NULL)
+       {
+               ERROR_MSG("Object type not compatible with this token class 0x%08X", object);
+
+               return false;
+       }
+
+       // Invalidate the object instance
+       fileObject->invalidate();
+
+       // Retrieve the filename of the object
+       std::string objectFilename = fileObject->getFilename();
+
+       // Attempt to delete the file
+       if (!tokenDir->remove(objectFilename))
+       {
+               ERROR_MSG("Failed to delete object file %s", objectFilename.c_str());
+
+               return false;
+       }
+
+       // Retrieve the filename of the lock
+       std::string lockFilename = fileObject->getLockname();
+
+       // Attempt to delete the lock
+       if (!tokenDir->remove(lockFilename))
+       {
+               ERROR_MSG("Failed to delete lock file %s", lockFilename.c_str());
+
+               return false;
+       }
+
+       objects.erase(object);
+
+       DEBUG_MSG("Deleted object %s", objectFilename.c_str());
+
+       gen->update();
+
+       gen->commit();
+
+       return true;
+}
+
+// Checks if the token is consistent
+bool OSToken::isValid()
+{
+       return valid;
+}
+
+// Invalidate the token (for instance if it is deleted)
+void OSToken::invalidate()
+{
+       valid = false;
+}
+
+// Delete the token
+bool OSToken::clearToken()
+{
+       MutexLocker lock(tokenMutex);
+
+       // Invalidate the token
+       invalidate();
+
+       // First, clear out all objects
+       objects.clear();
+
+       // Now, delete all files in the token directory
+       if (!tokenDir->refresh())
+       {
+               return false;
+       }
+
+       std::vector<std::string> tokenFiles = tokenDir->getFiles();
+
+       for (std::vector<std::string>::iterator i = tokenFiles.begin(); i != tokenFiles.end(); i++)
+       {
+               if (!tokenDir->remove(*i))
+               {
+                       ERROR_MSG("Failed to remove %s from token directory %s", i->c_str(), tokenPath.c_str());
+
+                       return false;
+               }
+       }
+
+       // Now remove the token directory
+       if (!tokenDir->rmdir(""))
+       {
+               ERROR_MSG("Failed to remove the token directory %s", tokenPath.c_str());
+
+               return false;
+       }
+
+       DEBUG_MSG("Token instance %s was succesfully cleared", tokenPath.c_str());
+
+       return true;
+}
+
+// Reset the token
+bool OSToken::resetToken(const ByteString& label)
+{
+       CK_ULONG flags;
+
+       if (!getTokenFlags(flags))
+       {
+               ERROR_MSG("Failed to get the token attributes");
+
+               return false;
+       }
+
+       // Clean up
+       std::set<OSObject*> cleanUp = getObjects();
+
+       MutexLocker lock(tokenMutex);
+
+       for (std::set<OSObject*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               ObjectFile* fileObject = dynamic_cast<ObjectFile*>(*i);
+               if (fileObject == NULL)
+               {
+                       ERROR_MSG("Object type not compatible with this token class 0x%08X", *i);
+
+                       return false;
+               }
+
+               // Invalidate the object instance
+               fileObject->invalidate();
+
+               // Retrieve the filename of the object
+               std::string objectFilename = fileObject->getFilename();
+
+               // Attempt to delete the file
+               if (!tokenDir->remove(objectFilename))
+               {
+                       ERROR_MSG("Failed to delete object file %s", objectFilename.c_str());
+
+                       return false;
+               }
+
+               // Retrieve the filename of the lock
+               std::string lockFilename = fileObject->getLockname();
+
+               // Attempt to delete the lock
+               if (!tokenDir->remove(lockFilename))
+               {
+                       ERROR_MSG("Failed to delete lock file %s", lockFilename.c_str());
+
+                       return false;
+               }
+
+               objects.erase(*i);
+
+               DEBUG_MSG("Deleted object %s", objectFilename.c_str());
+       }
+
+       // The user PIN has been removed
+       flags &= ~CKF_USER_PIN_INITIALIZED;
+       flags &= ~CKF_USER_PIN_COUNT_LOW;
+       flags &= ~CKF_USER_PIN_FINAL_TRY;
+       flags &= ~CKF_USER_PIN_LOCKED;
+       flags &= ~CKF_USER_PIN_TO_BE_CHANGED;
+
+       // Set new token attributes
+       OSAttribute tokenLabel(label);
+       OSAttribute tokenFlags(flags);
+
+       if (!tokenObject->setAttribute(CKA_OS_TOKENLABEL, tokenLabel) ||
+           !tokenObject->setAttribute(CKA_OS_TOKENFLAGS, tokenFlags))
+       {
+               ERROR_MSG("Failed to set the token attributes");
+
+               return false;
+       }
+
+       if (tokenObject->attributeExists(CKA_OS_USERPIN) &&
+           !tokenObject->deleteAttribute(CKA_OS_USERPIN))
+       {
+               ERROR_MSG("Failed to remove USERPIN");
+
+               return false;
+       }
+
+       DEBUG_MSG("Token instance %s was succesfully reset", tokenPath.c_str());
+
+       gen->update();
+       gen->commit();
+
+       return true;
+}
+
+// Index the token
+bool OSToken::index(bool isFirstTime /* = false */)
+{
+       // No access to object mutable fields before
+       MutexLocker lock(tokenMutex);
+
+       // Check if re-indexing is required
+       if (!isFirstTime && (!valid || !gen->wasUpdated()))
+       {
+               DEBUG_MSG("No re-indexing is required");
+
+               return true;
+       }
+
+       // Check the integrity
+       if (!tokenDir->refresh() || !tokenObject->valid)
+       {
+               ERROR_MSG("Token integrity check failed");
+
+               valid = false;
+
+               return false;
+       }
+
+       DEBUG_MSG("Token %s has changed", tokenPath.c_str());
+
+       // Retrieve the directory listing
+       std::vector<std::string> tokenFiles = tokenDir->getFiles();
+
+       // Filter out the objects
+       std::set<std::string> newSet;
+
+       for (std::vector<std::string>::iterator i = tokenFiles.begin(); i != tokenFiles.end(); i++)
+       {
+               if ((i->size() > 7) &&
+                   (!(i->substr(i->size() - 7).compare(".object"))) &&
+                   (i->compare("token.object")))
+               {
+                       newSet.insert(*i);
+               }
+               else
+               {
+                       DEBUG_MSG("Ignored file %s", i->c_str());
+               }
+       }
+
+       // Compute the changes compared to the last list of files
+       std::set<std::string> addedFiles;
+       std::set<std::string> removedFiles;
+
+       if (!isFirstTime)
+       {
+               // First compute which files were added
+               for (std::set<std::string>::iterator i = newSet.begin(); i != newSet.end(); i++)
+               {
+                       if (currentFiles.find(*i) == currentFiles.end())
+                       {
+                               addedFiles.insert(*i);
+                       }
+               }
+
+               // Now compute which files were removed
+               for (std::set<std::string>::iterator i = currentFiles.begin(); i != currentFiles.end(); i++)
+               {
+                       if (newSet.find(*i) == newSet.end())
+                       {
+                               removedFiles.insert(*i);
+                       }
+               }
+       }
+       else
+       {
+               addedFiles = newSet;
+       }
+
+       currentFiles = newSet;
+
+       DEBUG_MSG("%d objects were added and %d objects were removed", addedFiles.size(), removedFiles.size());
+       DEBUG_MSG("Current directory set contains %d objects", currentFiles.size());
+
+       // Now update the set of objects
+
+       // Add new objects
+       for (std::set<std::string>::iterator i = addedFiles.begin(); i != addedFiles.end(); i++)
+       {
+               if ((i->find_last_of('.') == std::string::npos) ||
+                   (i->substr(i->find_last_of('.')) != ".object"))
+               {
+                       continue;
+               }
+
+               std::string lockName(*i);
+               lockName.replace(lockName.find_last_of('.'), std::string::npos, ".lock");
+
+               // Create a new token object for the added file
+               ObjectFile* newObject = new ObjectFile(this, tokenPath + OS_PATHSEP + *i, tokenPath + OS_PATHSEP + lockName);
+
+               // Add the object, even invalid ones.
+               // This is so the we can read the attributes once
+               // the other process has finished writing to disc.
+               DEBUG_MSG("(0x%08X) New object %s (0x%08X) added", this, newObject->getFilename().c_str(), newObject);
+               objects.insert(newObject);
+               allObjects.insert(newObject);
+       }
+
+       // Remove deleted objects
+       std::set<OSObject*> newObjects;
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ObjectFile* fileObject = dynamic_cast<ObjectFile*>((*i));
+               if (fileObject == NULL)
+               {
+                       ERROR_MSG("Object type not compatible with this token class 0x%08X", (*i));
+
+                       return false;
+               }
+
+               DEBUG_MSG("Processing %s (0x%08X)", fileObject->getFilename().c_str(), *i);
+
+               if (removedFiles.find(fileObject->getFilename()) == removedFiles.end())
+               {
+                       DEBUG_MSG("Adding object %s", fileObject->getFilename().c_str());
+                       // This object gets to stay in the set
+                       newObjects.insert(*i);
+               }
+               else
+               {
+                       fileObject->invalidate();
+               }
+       }
+
+       // Set the new objects
+       objects = newObjects;
+
+       DEBUG_MSG("The token now contains %d objects", objects.size());
+
+       return true;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/OSToken.h b/SoftHSMv2/src/lib/object_store/OSToken.h
new file mode 100644 (file)
index 0000000..4ba5b2c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSToken.h
+
+ The token class; a token is stored in a directory containing several files.
+ Each object is stored in a separate file and a token object is present that
+ has the token specific attributes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSTOKEN_H
+#define _SOFTHSM_V2_OSTOKEN_H
+
+#include "config.h"
+#include "ObjectStoreToken.h"
+#include "OSAttribute.h"
+#include "ObjectFile.h"
+#include "Directory.h"
+#include "Generation.h"
+#include "UUID.h"
+#include "MutexFactory.h"
+#include "cryptoki.h"
+#include <string>
+#include <set>
+#include <map>
+#include <list>
+
+class OSToken : public ObjectStoreToken
+{
+public:
+       // Constructor
+       OSToken(const std::string inTokenPath);
+
+       // Create a new token
+       static OSToken* createToken(const std::string basePath, const std::string tokenDir, const ByteString& label, const ByteString& serial);
+
+       // Access an existing token
+       static OSToken* accessToken(const std::string &basePath, const std::string &tokenDir);
+
+       // Constructor for new tokens
+       OSToken(const std::string tokenPath, const ByteString& label, const ByteString& serialNumber);
+
+       // Set the SO PIN
+       virtual bool setSOPIN(const ByteString& soPINBlob);
+
+       // Get the SO PIN
+       virtual bool getSOPIN(ByteString& soPINBlob);
+
+       // Set the user PIN
+       virtual bool setUserPIN(ByteString userPINBlob);
+
+       // Get the user PIN
+       virtual bool getUserPIN(ByteString& userPINBlob);
+
+       // Get the token flags
+       virtual bool getTokenFlags(CK_ULONG& flags);
+
+       // Set the token flags
+       virtual bool setTokenFlags(const CK_ULONG flags);
+
+       // Retrieve the token label
+       virtual bool getTokenLabel(ByteString& label);
+
+       // Retrieve the token serial
+       virtual bool getTokenSerial(ByteString& serial);
+
+       // Retrieve objects
+       virtual std::set<OSObject*> getObjects();
+
+       // Insert objects into the given set
+       virtual void getObjects(std::set<OSObject*> &inObjects);
+
+       // Create a new object
+       virtual OSObject* createObject();
+
+       // Delete an object
+       virtual bool deleteObject(OSObject* object);
+
+       // Destructor
+       virtual ~OSToken();
+
+       // Checks if the token is consistent
+       virtual bool isValid();
+
+       // Invalidate the token (for instance if it is deleted)
+       virtual void invalidate();
+
+       // Delete the token
+       virtual bool clearToken();
+
+       // Reset the token
+       virtual bool resetToken(const ByteString& label);
+
+private:
+       // ObjectFile instances can call the index() function
+       friend class ObjectFile;
+
+       // Index the token
+       bool index(bool isFirstTime = false);
+
+       // Is the token consistent and valid?
+       bool valid;
+
+       // The token path
+       std::string tokenPath;
+
+       // The current objects of the token
+       std::set<OSObject*> objects;
+
+       // All the objects ever associated with this token
+       //
+       // This set is kept to be able to clean up when the token
+       // instance is discarded; in case the contents of a token
+       // change, some objects may disappear but we cannot simply
+       // delete them since they may still be referenced from an
+       // object outside of this class.
+       std::set<OSObject*> allObjects;
+
+       // The current list of files
+       std::set<std::string> currentFiles;
+
+       // The token object
+       ObjectFile* tokenObject;
+
+       // Generation control
+       Generation* gen;
+
+       // The directory object for this token
+       Directory* tokenDir;
+
+       // For thread safeness
+       Mutex* tokenMutex;
+};
+
+#endif // !_SOFTHSM_V2_OSTOKEN_H
+
diff --git a/SoftHSMv2/src/lib/object_store/ObjectFile.cpp b/SoftHSMv2/src/lib/object_store/ObjectFile.cpp
new file mode 100644 (file)
index 0000000..f3becbe
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ObjectFile.h
+
+ This class represents object files
+ *****************************************************************************/
+
+#include "config.h"
+#include "ObjectFile.h"
+#include "OSToken.h"
+#include "OSPathSep.h"
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <set>
+
+// Attribute types
+#define BOOLEAN_ATTR                   0x1
+#define ULONG_ATTR                     0x2
+#define BYTESTR_ATTR                   0x3
+#define ATTRMAP_ATTR                   0x4
+#define MECHSET_ATTR                   0x5
+
+// Constructor
+ObjectFile::ObjectFile(OSToken* parent, std::string inPath, std::string inLockpath, bool isNew /* = false */)
+{
+       path = inPath;
+       gen = Generation::create(path);
+       objectMutex = MutexFactory::i()->getMutex();
+       valid = (gen != NULL) && (objectMutex != NULL);
+       token = parent;
+       inTransaction = false;
+       transactionLockFile = NULL;
+       lockpath = inLockpath;
+
+       if (!valid) return;
+
+       if (!isNew)
+       {
+               DEBUG_MSG("Opened existing object %s", path.c_str());
+
+               refresh(true);
+       }
+       else
+       {
+               DEBUG_MSG("Created new object %s", path.c_str());
+
+               // Create an empty object file
+               store();
+       }
+
+}
+
+// Destructor
+ObjectFile::~ObjectFile()
+{
+       discardAttributes();
+
+       if (gen != NULL)
+       {
+               delete gen;
+       }
+
+       MutexFactory::i()->recycleMutex(objectMutex);
+}
+
+// Check if the specified attribute exists
+bool ObjectFile::attributeExists(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       return valid && (attributes[type] != NULL);
+}
+
+// Retrieve the specified attribute
+OSAttribute ObjectFile::getAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return OSAttribute((unsigned long)0);
+       }
+
+       return *attr;
+}
+
+bool ObjectFile::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isBooleanAttribute())
+       {
+               return attr->getBooleanValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
+               return val;
+       }
+}
+
+unsigned long ObjectFile::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isUnsignedLongAttribute())
+       {
+               return attr->getUnsignedLongValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
+               return val;
+       }
+}
+
+ByteString ObjectFile::getByteStringValue(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       ByteString val;
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isByteStringAttribute())
+       {
+               return attr->getByteStringValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
+               return val;
+       }
+}
+
+// Retrieve the next attribute type
+CK_ATTRIBUTE_TYPE ObjectFile::nextAttributeType(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*>::iterator n = attributes.upper_bound(type);
+
+       // skip null attributes
+       while ((n != attributes.end()) && (n->second == NULL))
+               ++n;
+
+       // return type or CKA_CLASS (= 0)
+       if (n == attributes.end())
+       {
+               return CKA_CLASS;
+       }
+       else
+       {
+               return n->first;
+       }
+}
+
+// Set the specified attribute
+bool ObjectFile::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
+{
+       if (!valid)
+       {
+               DEBUG_MSG("Cannot update invalid object %s", path.c_str());
+
+               return false;
+       }
+
+       {
+               MutexLocker lock(objectMutex);
+
+               if (attributes[type] != NULL)
+               {
+                       delete attributes[type];
+
+                       attributes[type] = NULL;
+               }
+
+               attributes[type] = new OSAttribute(attribute);
+       }
+
+       store();
+
+       return valid;
+}
+
+// Delete the specified attribute
+bool ObjectFile::deleteAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       if (!valid)
+       {
+               DEBUG_MSG("Cannot update invalid object %s", path.c_str());
+
+               return false;
+       }
+
+       {
+               MutexLocker lock(objectMutex);
+
+               if (attributes[type] == NULL)
+               {
+                       DEBUG_MSG("Cannot delete attribute that doesn't exist in object %s", path.c_str());
+
+                       return false;
+               }
+
+               delete attributes[type];
+               attributes.erase(type);
+       }
+
+       store();
+
+       return valid;
+}
+
+// The validity state of the object (refresh from disk as a side effect)
+bool ObjectFile::isValid()
+{
+       refresh();
+
+       return valid;
+}
+
+// Invalidate the object file externally; this method is normally
+// only called by the OSToken class in case an object file has
+// been deleted.
+void ObjectFile::invalidate()
+{
+       valid = false;
+
+       discardAttributes();
+}
+
+// Refresh the object if necessary
+void ObjectFile::refresh(bool isFirstTime /* = false */)
+{
+       // Check if we're in the middle of a transaction
+       if (inTransaction)
+       {
+               DEBUG_MSG("The object is in a transaction");
+
+               return;
+       }
+
+       // Refresh the associated token if set
+       if (!isFirstTime && (token != NULL))
+       {
+               // This may cause this instance to become invalid
+               token->index();
+       }
+
+       // Check the generation
+       if (!isFirstTime && (gen == NULL || !gen->wasUpdated()))
+       {
+               DEBUG_MSG("The object generation has not been updated");
+
+               return;
+       }
+
+       File objectFile(path);
+
+       if (!objectFile.isValid())
+       {
+               DEBUG_MSG("Object %s is invalid", path.c_str());
+
+               valid = false;
+
+               return;
+       }
+
+       objectFile.lock();
+
+       if (objectFile.isEmpty())
+       {
+               DEBUG_MSG("Object %s is empty", path.c_str());
+
+               valid = false;
+
+               return;
+       }
+
+       DEBUG_MSG("Object %s has changed", path.c_str());
+
+       // Discard the existing set of attributes
+       discardAttributes();
+
+       MutexLocker lock(objectMutex);
+
+       // Read back the generation number
+       unsigned long curGen;
+
+       if (!objectFile.readULong(curGen))
+       {
+               if (!objectFile.isEOF())
+               {
+                       DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                       valid = false;
+
+                       objectFile.unlock();
+
+                       return;
+               }
+       }
+       else
+       {
+               gen->set(curGen);
+       }
+
+       // Read back the attributes
+       while (!objectFile.isEOF())
+       {
+               unsigned long p11AttrType;
+               unsigned long osAttrType;
+
+               if (!objectFile.readULong(p11AttrType))
+               {
+                       if (objectFile.isEOF())
+                       {
+                               break;
+                       }
+
+                       DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                       valid = false;
+
+                       objectFile.unlock();
+
+                       return;
+               }
+
+               if (!objectFile.readULong(osAttrType))
+               {
+                       DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                       valid = false;
+
+                       objectFile.unlock();
+
+                       return;
+               }
+
+               // Depending on the type, read back the actual value
+               if (osAttrType == BOOLEAN_ATTR)
+               {
+                       bool value;
+
+                       if (!objectFile.readBool(value))
+                       {
+                               DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                               valid = false;
+
+                               objectFile.unlock();
+
+                               return;
+                       }
+
+                       if (attributes[p11AttrType] != NULL)
+                       {
+                               delete attributes[p11AttrType];
+                       }
+
+                       attributes[p11AttrType] = new OSAttribute(value);
+               }
+               else if (osAttrType == ULONG_ATTR)
+               {
+                       unsigned long value;
+
+                       if (!objectFile.readULong(value))
+                       {
+                               DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                               valid = false;
+
+                               objectFile.unlock();
+
+                               return;
+                       }
+
+                       if (attributes[p11AttrType] != NULL)
+                       {
+                               delete attributes[p11AttrType];
+                       }
+
+                       attributes[p11AttrType] = new OSAttribute(value);
+               }
+               else if (osAttrType == BYTESTR_ATTR)
+               {
+                       ByteString value;
+
+                       if (!objectFile.readByteString(value))
+                       {
+                               DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                               valid = false;
+
+                               objectFile.unlock();
+
+                               return;
+                       }
+
+                       if (attributes[p11AttrType] != NULL)
+                       {
+                               delete attributes[p11AttrType];
+                       }
+
+                       attributes[p11AttrType] = new OSAttribute(value);
+               }
+               else if (osAttrType == MECHSET_ATTR)
+               {
+                       std::set<CK_MECHANISM_TYPE> value;
+
+                       if (!objectFile.readMechanismTypeSet(value))
+                       {
+                               DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                               valid = false;
+
+                               objectFile.unlock();
+
+                               return;
+                       }
+
+                       if (attributes[p11AttrType] != NULL)
+                       {
+                               delete attributes[p11AttrType];
+                       }
+
+                       attributes[p11AttrType] = new OSAttribute(value);
+               }
+               else if (osAttrType == ATTRMAP_ATTR)
+               {
+                       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
+
+                       if (!objectFile.readAttributeMap(value))
+                       {
+                               DEBUG_MSG("Corrupt object file %s", path.c_str());
+
+                               valid = false;
+
+                               objectFile.unlock();
+
+                               return;
+                       }
+
+                       if (attributes[p11AttrType] != NULL)
+                       {
+                               delete attributes[p11AttrType];
+                       }
+
+                       attributes[p11AttrType] = new OSAttribute(value);
+               }
+               else
+               {
+                       DEBUG_MSG("Corrupt object file %s with unknown attribute of type %d", path.c_str(), osAttrType);
+
+                       valid = false;
+
+                       objectFile.unlock();
+
+                       return;
+               }
+       }
+
+       objectFile.unlock();
+
+       valid = true;
+}
+
+// Common write part in store()
+// called with objectFile locked and returns with objectFile unlocked
+bool ObjectFile::writeAttributes(File &objectFile)
+{
+       if (!gen->sync(objectFile))
+       {
+               DEBUG_MSG("Failed to synchronize generation number from object %s", path.c_str());
+
+               objectFile.unlock();
+
+               return false;
+       }
+
+       if (!objectFile.truncate())
+       {
+               DEBUG_MSG("Failed to reset object %s", path.c_str());
+
+               objectFile.unlock();
+
+               return false;
+       }
+
+       gen->update();
+
+       unsigned long newGen = gen->get();
+
+       if (!objectFile.writeULong(newGen))
+       {
+               DEBUG_MSG("Failed to write new generation number to object %s", path.c_str());
+
+               gen->rollback();
+
+               objectFile.unlock();
+
+               return false;
+       }
+
+
+       for (std::map<CK_ATTRIBUTE_TYPE, OSAttribute*>::iterator i = attributes.begin(); i != attributes.end(); i++)
+       {
+               if (i->second == NULL)
+               {
+                       continue;
+               }
+
+               unsigned long p11AttrType = i->first;
+
+               if (!objectFile.writeULong(p11AttrType))
+               {
+                       DEBUG_MSG("Failed to write PKCS #11 attribute type to object %s", path.c_str());
+
+                       objectFile.unlock();
+
+                       return false;
+               }
+
+               if (i->second->isBooleanAttribute())
+               {
+                       unsigned long osAttrType = BOOLEAN_ATTR;
+                       bool value = i->second->getBooleanValue();
+
+                       if (!objectFile.writeULong(osAttrType) || !objectFile.writeBool(value))
+                       {
+                               DEBUG_MSG("Failed to write attribute to object %s", path.c_str());
+
+                               objectFile.unlock();
+
+                               return false;
+                       }
+               }
+               else if (i->second->isUnsignedLongAttribute())
+               {
+                       unsigned long osAttrType = ULONG_ATTR;
+                       unsigned long value = i->second->getUnsignedLongValue();
+
+                       if (!objectFile.writeULong(osAttrType) || !objectFile.writeULong(value))
+                       {
+                               DEBUG_MSG("Failed to write attribute to object %s", path.c_str());
+
+                               objectFile.unlock();
+
+                               return false;
+                       }
+               }
+               else if (i->second->isByteStringAttribute())
+               {
+                       unsigned long osAttrType = BYTESTR_ATTR;
+                       const ByteString& value = i->second->getByteStringValue();
+
+                       if (!objectFile.writeULong(osAttrType) || !objectFile.writeByteString(value))
+                       {
+                               DEBUG_MSG("Failed to write attribute to object %s", path.c_str());
+
+                               objectFile.unlock();
+
+                               return false;
+                       }
+               }
+               else if (i->second->isMechanismTypeSetAttribute())
+               {
+                       unsigned long osAttrType = MECHSET_ATTR;
+                       const std::set<CK_MECHANISM_TYPE>& value = i->second->getMechanismTypeSetValue();
+
+                       if (!objectFile.writeULong(osAttrType) || !objectFile.writeMechanismTypeSet(value))
+                       {
+                               DEBUG_MSG("Failed to write attribute to object %s", path.c_str());
+
+                               objectFile.unlock();
+
+                               return false;
+                       }
+               }
+               else if (i->second->isAttributeMapAttribute())
+               {
+                       unsigned long osAttrType = ATTRMAP_ATTR;
+                       const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& value = i->second->getAttributeMapValue();
+
+                       if (!objectFile.writeULong(osAttrType) || !objectFile.writeAttributeMap(value))
+                       {
+                               DEBUG_MSG("Failed to write attribute to object %s", path.c_str());
+
+                               objectFile.unlock();
+
+                               return false;
+                       }
+               }
+               else
+               {
+                       DEBUG_MSG("Unknown attribute type for object %s", path.c_str());
+
+                       objectFile.unlock();
+
+                       return false;
+               }
+       }
+
+       objectFile.unlock();
+
+       return true;
+}
+
+// Write the object to background storage
+void ObjectFile::store(bool isCommit /* = false */)
+{
+       // Check if we're in the middle of a transaction
+       if (!isCommit && inTransaction)
+       {
+               return;
+       }
+
+       if (!valid)
+       {
+               DEBUG_MSG("Cannot write back an invalid object %s", path.c_str());
+
+               return;
+       }
+
+       File objectFile(path, true, true, true, false);
+
+       if (!objectFile.isValid())
+       {
+               DEBUG_MSG("Cannot open object %s for writing", path.c_str());
+
+               valid = false;
+
+               return;
+       }
+
+       objectFile.lock();
+
+       if (!isCommit) {
+               MutexLocker lock(objectMutex);
+               File lockFile(lockpath, false, true, true);
+
+               if (!writeAttributes(objectFile))
+               {
+                       valid = false;
+
+                       return;
+               }
+       }
+       else
+       {
+               if (!writeAttributes(objectFile))
+               {
+                       valid = false;
+
+                       return;
+               }
+       }
+
+       valid = true;
+}
+
+// Discard the cached attributes
+void ObjectFile::discardAttributes()
+{
+       MutexLocker lock(objectMutex);
+
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*> cleanUp = attributes;
+       attributes.clear();
+
+       for (std::map<CK_ATTRIBUTE_TYPE, OSAttribute*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               if (i->second == NULL)
+               {
+                       continue;
+               }
+
+               delete i->second;
+               i->second = NULL;
+       }
+}
+
+
+// Returns the file name of the object
+std::string ObjectFile::getFilename() const
+{
+       if ((path.find_last_of(OS_PATHSEP) != std::string::npos) &&
+           (path.find_last_of(OS_PATHSEP) < path.size()))
+       {
+               return path.substr(path.find_last_of(OS_PATHSEP) + 1);
+       }
+       else
+       {
+               return path;
+       }
+}
+
+// Returns the file name of the lock
+std::string ObjectFile::getLockname() const
+{
+       if ((lockpath.find_last_of(OS_PATHSEP) != std::string::npos) &&
+           (lockpath.find_last_of(OS_PATHSEP) < lockpath.size()))
+       {
+               return lockpath.substr(lockpath.find_last_of(OS_PATHSEP) + 1);
+       }
+       else
+       {
+               return lockpath;
+       }
+}
+
+// Start an attribute set transaction; this method is used when - for
+// example - a key is generated and all its attributes need to be
+// persisted in one go.
+//
+// N.B.: Starting a transaction locks the object!
+bool ObjectFile::startTransaction(Access)
+{
+       MutexLocker lock(objectMutex);
+
+       if (inTransaction)
+       {
+               return false;
+       }
+
+       transactionLockFile = new File(lockpath, false, true, true);
+
+       if (!transactionLockFile->isValid() || !transactionLockFile->lock())
+       {
+               delete transactionLockFile;
+               transactionLockFile = NULL;
+
+               ERROR_MSG("Failed to lock file %s for attribute transaction", lockpath.c_str());
+
+               return false;
+       }
+
+       inTransaction = true;
+
+       return true;
+}
+
+// Commit an attribute transaction
+bool ObjectFile::commitTransaction()
+{
+       MutexLocker lock(objectMutex);
+
+       if (!inTransaction)
+       {
+               return false;
+       }
+
+       if (transactionLockFile == NULL)
+       {
+               ERROR_MSG("Transaction lock file instance invalid!");
+
+               return false;
+       }
+
+       // Special store case
+       store(true);
+
+       if (!valid)
+       {
+               return false;
+       }
+
+       transactionLockFile->unlock();
+
+       delete transactionLockFile;
+       transactionLockFile = NULL;
+       inTransaction = false;
+
+       return true;
+}
+
+// Abort an attribute transaction; loads back the previous version of the object from disk
+bool ObjectFile::abortTransaction()
+{
+       {
+               MutexLocker lock(objectMutex);
+
+               if (!inTransaction)
+               {
+                       return false;
+               }
+
+               if (transactionLockFile == NULL)
+               {
+                       ERROR_MSG("Transaction lock file instance invalid!");
+
+                       return false;
+               }
+
+               transactionLockFile->unlock();
+
+               delete transactionLockFile;
+               transactionLockFile = NULL;
+               inTransaction = false;
+       }
+
+       // Force reload from disk
+       refresh(true);
+
+       return true;
+}
+
+// Destroy the object; WARNING: pointers to the object become invalid after this call
+bool ObjectFile::destroyObject()
+{
+       if (token == NULL)
+       {
+               ERROR_MSG("Cannot destroy an object that is not associated with a token");
+
+               return false;
+       }
+
+       return token->deleteObject(this);
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/ObjectFile.h b/SoftHSMv2/src/lib/object_store/ObjectFile.h
new file mode 100644 (file)
index 0000000..a13d835
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ ObjectFile.h
+
+ This class represents object files
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTFILE_H
+#define _SOFTHSM_V2_OBJECTFILE_H
+
+#include "config.h"
+#include "File.h"
+#include "Generation.h"
+#include "ByteString.h"
+#include "OSAttribute.h"
+#include "MutexFactory.h"
+#include <string>
+#include <map>
+#include <time.h>
+#include "cryptoki.h"
+#include "OSObject.h"
+
+// OSToken forward declaration
+class OSToken;
+
+class ObjectFile : public OSObject
+{
+public:
+       // Constructor
+       ObjectFile(OSToken* parent, const std::string inPath, const std::string inLockpath, bool isNew = false);
+
+       // Destructor
+       virtual ~ObjectFile();
+
+       // Check if the specified attribute exists
+       virtual bool attributeExists(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the specified attribute
+       virtual OSAttribute getAttribute(CK_ATTRIBUTE_TYPE type);
+       virtual bool getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val);
+       virtual unsigned long getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val);
+       virtual ByteString getByteStringValue(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the next attribute type
+       virtual CK_ATTRIBUTE_TYPE nextAttributeType(CK_ATTRIBUTE_TYPE type);
+
+       // Set the specified attribute
+       virtual bool setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute);
+
+       // Delete the specified attribute
+       virtual bool deleteAttribute(CK_ATTRIBUTE_TYPE type);
+
+       // The validity state of the object (refresh from disk as a side effect)
+       virtual bool isValid();
+
+       // Invalidate the object file externally; this method is normally
+       // only called by the OSToken class in case an object file has
+       // been deleted.
+       void invalidate();
+
+       // Returns the file name of the object
+       std::string getFilename() const;
+
+       // Returns the file name of the lock
+       std::string getLockname() const;
+
+       // Start an attribute set transaction; this method is used when - for
+       // example - a key is generated and all its attributes need to be
+       // persisted in one go.
+       //
+       // N.B.: Starting a transaction locks the object!
+       //
+       // Function returns false in case a transaction is already in progress
+       virtual bool startTransaction(Access access);
+
+       // Commit an attribute transaction; returns false if no transaction is in progress
+       virtual bool commitTransaction();
+
+       // Abort an attribute transaction; loads back the previous version of the object from disk;
+       // returns false if no transaction was in progress
+       virtual bool abortTransaction();
+
+       // Destroys the object; WARNING: pointers to the object become invalid after this
+       // call!
+       virtual bool destroyObject();
+
+private:
+       // OSToken instances can read valid (vs calling IsValid() from index())
+       friend class OSToken;
+
+       // Refresh the object if necessary
+       void refresh(bool isFirstTime = false);
+
+       // Write the object to background storage
+       void store(bool isCommit = false);
+
+       // Store subroutine
+       bool writeAttributes(File &objectFile);
+
+       // Discard the cached attributes
+       void discardAttributes();
+
+       // The path to the file
+       std::string path;
+
+       // The Generation object that is used to detect changes in the
+        // object file from other SoftHSM instances
+       Generation* gen;
+
+       // The object's raw attributes
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*> attributes;
+
+       // The object's validity state
+       bool valid;
+
+       // The token this object is associated with
+       OSToken* token;
+
+       // Mutex object for thread-safeness
+       Mutex* objectMutex;
+
+       // Is the object undergoing an attribute transaction?
+       bool inTransaction;
+       File* transactionLockFile;
+       std::string lockpath;
+};
+
+#endif // !_SOFTHSM_V2_OBJECTFILE_H
+
diff --git a/SoftHSMv2/src/lib/object_store/ObjectStore.cpp b/SoftHSMv2/src/lib/object_store/ObjectStore.cpp
new file mode 100644 (file)
index 0000000..3855d9d
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ObjectStore.h
+
+ The object store manages the separate tokens that the SoftHSM supports. Each
+ token is organised as a directory containing files that are contain the
+ token's objects. The object store is initialised with a root directory from
+ which it enumerates the tokens.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "ObjectStore.h"
+#include "Directory.h"
+#include "ObjectStoreToken.h"
+#include "OSPathSep.h"
+#include "UUID.h"
+#include <stdio.h>
+
+// Constructor
+ObjectStore::ObjectStore(std::string inStorePath)
+{
+       storePath = inStorePath;
+       valid = false;
+       storeMutex = MutexFactory::i()->getMutex();
+
+       MutexLocker lock(storeMutex);
+
+       // Find all tokens in the specified path
+       Directory storeDir(storePath);
+
+       if (!storeDir.isValid())
+       {
+               WARNING_MSG("Failed to enumerate object store in %s", storePath.c_str());
+
+               return;
+       }
+
+       // Assume that all subdirectories are tokens
+       std::vector<std::string> dirs = storeDir.getSubDirs();
+
+       for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); i++)
+       {
+               // Create a token instance
+               ObjectStoreToken* token = ObjectStoreToken::accessToken(storePath, *i);
+
+               if (!token->isValid())
+               {
+                       ERROR_MSG("Failed to open token %s", i->c_str());
+
+                       delete token;
+
+                       // Silently ignore tokens that we do not have access to
+                       continue;
+               }
+
+               tokens.push_back(token);
+               allTokens.push_back(token);
+       }
+
+       valid = true;
+}
+
+// Destructor
+ObjectStore::~ObjectStore()
+{
+       {
+               MutexLocker lock(storeMutex);
+
+               // Clean up
+               tokens.clear();
+
+               for (std::vector<ObjectStoreToken*>::iterator i = allTokens.begin(); i != allTokens.end(); i++)
+               {
+                       delete *i;
+               }
+       }
+
+       MutexFactory::i()->recycleMutex(storeMutex);
+}
+
+// Check if the object store is valid
+bool ObjectStore::isValid()
+{
+       return valid;
+}
+
+// Return the number of tokens that is present
+size_t ObjectStore::getTokenCount()
+{
+       MutexLocker lock(storeMutex);
+
+       return tokens.size();
+}
+
+// Return a pointer to the n-th token (counting starts at 0)
+ObjectStoreToken* ObjectStore::getToken(size_t whichToken)
+{
+       MutexLocker lock(storeMutex);
+
+       if (whichToken >= tokens.size())
+       {
+               return NULL;
+       }
+
+       return tokens[whichToken];
+}
+
+// Create a new token
+ObjectStoreToken* ObjectStore::newToken(const ByteString& label)
+{
+       MutexLocker lock(storeMutex);
+
+       // Generate a UUID for the token
+       std::string tokenUUID = UUID::newUUID();
+
+       // Convert the UUID to a serial number
+       std::string serialNumber = tokenUUID.substr(19, 4) + tokenUUID.substr(24);
+       ByteString serial((const unsigned char*) serialNumber.c_str(), serialNumber.size());
+
+       // Create the token
+       ObjectStoreToken* newToken = ObjectStoreToken::createToken(storePath, tokenUUID, label, serial);
+
+       if (newToken != NULL)
+       {
+               tokens.push_back(newToken);
+               allTokens.push_back(newToken);
+       }
+
+       return newToken;
+}
+
+// Destroy a token
+bool ObjectStore::destroyToken(ObjectStoreToken *token)
+{
+       MutexLocker lock(storeMutex);
+
+       // Find the token
+       for (std::vector<ObjectStoreToken*>::iterator i = tokens.begin(); i != tokens.end(); i++)
+       {
+               if (*i == token)
+               {
+                       // Found the token, now destroy the token
+                       if (!token->clearToken())
+                       {
+                               ERROR_MSG("Failed to clear token instance");
+
+                               return false;
+                       }
+
+                       // And remove it from the vector
+                       tokens.erase(i);
+
+                       return true;
+               }
+       }
+
+       ERROR_MSG("Could not find the token instance to destroy");
+
+       return false;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/ObjectStore.h b/SoftHSMv2/src/lib/object_store/ObjectStore.h
new file mode 100644 (file)
index 0000000..e8ecd1a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ObjectStore.h
+
+ The object store manages the separate tokens that the SoftHSM supports. Each
+ token is organised as a directory containing files that are contain the
+ token's objects. The object store is initialised with a root directory from
+ which it enumerates the tokens.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTSTORE_H
+#define _SOFTHSM_V2_OBJECTSTORE_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "ObjectStoreToken.h"
+#include "MutexFactory.h"
+#include <string>
+#include <vector>
+
+class ObjectStore
+{
+public:
+       // Constructor
+       ObjectStore(std::string inStorePath);
+
+       // Destructor
+       virtual ~ObjectStore();
+
+       // Return the number of tokens that is present
+       size_t getTokenCount();
+
+       // Return a pointer to the n-th token (counting starts at 0)
+       ObjectStoreToken* getToken(size_t whichToken);
+
+       // Create a new token
+       ObjectStoreToken* newToken(const ByteString& label);
+
+       // Destroy a token
+       bool destroyToken(ObjectStoreToken* token);
+
+       // Check if the object store is valid
+       bool isValid();
+
+private:
+       // The tokens
+       std::vector<ObjectStoreToken*> tokens;
+
+       // All tokens
+       std::vector<ObjectStoreToken*> allTokens;
+
+       // The object store root directory
+       std::string storePath;
+
+       // The status
+       bool valid;
+
+       // Object store synchronisation
+       Mutex* storeMutex;
+};
+
+#endif // !_SOFTHSM_V2_OBJECTSTORE_H
+
diff --git a/SoftHSMv2/src/lib/object_store/ObjectStoreToken.cpp b/SoftHSMv2/src/lib/object_store/ObjectStoreToken.cpp
new file mode 100644 (file)
index 0000000..24c2049
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectStoreToken.cpp
+
+ The object store abstract token base class
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "ObjectStoreToken.h"
+
+// OSToken is a concrete implementation of ObjectStoreToken base class.
+#include "OSToken.h"
+
+#ifdef HAVE_OBJECTSTORE_BACKEND_DB
+// DBToken is a concrete implementation of ObjectSToreToken that stores the objects and attributes in an SQLite3 database.
+#include "DBToken.h"
+#endif
+
+typedef ObjectStoreToken* (*CreateToken)(const std::string , const std::string , const ByteString& , const ByteString& );
+typedef ObjectStoreToken* (*AccessToken)(const std::string &, const std::string &);
+
+static CreateToken static_createToken = reinterpret_cast<CreateToken>(OSToken::createToken);
+static AccessToken static_accessToken = reinterpret_cast<AccessToken>(OSToken::accessToken);
+
+// Create a new token
+/*static*/ bool ObjectStoreToken::selectBackend(const std::string &backend)
+{
+       if (backend == "file")
+       {
+               static_createToken = reinterpret_cast<CreateToken>(OSToken::createToken);
+               static_accessToken = reinterpret_cast<AccessToken>(OSToken::accessToken);
+       }
+#ifdef HAVE_OBJECTSTORE_BACKEND_DB
+       else if (backend == "db")
+       {
+               static_createToken = reinterpret_cast<CreateToken>(DBToken::createToken);
+               static_accessToken = reinterpret_cast<AccessToken>(DBToken::accessToken);
+       }
+#endif
+       else
+       {
+               ERROR_MSG("Unknown value (%s) for objectstore.backend in configuration", backend.c_str());
+               return false;
+       }
+
+       return true;
+}
+
+ObjectStoreToken* ObjectStoreToken::createToken(const std::string basePath, const std::string tokenDir, const ByteString& label, const ByteString& serial)
+{
+       return static_createToken(basePath,tokenDir,label,serial);
+}
+
+// Access an existing token
+/*static*/ ObjectStoreToken *ObjectStoreToken::accessToken(const std::string &basePath, const std::string &tokenDir)
+{
+       return static_accessToken(basePath, tokenDir);
+}
diff --git a/SoftHSMv2/src/lib/object_store/ObjectStoreToken.h b/SoftHSMv2/src/lib/object_store/ObjectStoreToken.h
new file mode 100644 (file)
index 0000000..668dccc
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectStoreToken.h
+
+ The object store abstract token base class;
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTSTORETOKEN_H
+#define _SOFTHSM_V2_OBJECTSTORETOKEN_H
+
+#include "config.h"
+#include "OSObject.h"
+#include <string>
+#include <set>
+
+class ObjectStoreToken
+{
+public:
+       // Select the type of backend to use for storing token objects.
+       static bool selectBackend(const std::string& backend);
+
+       // Create a new token
+       static ObjectStoreToken* createToken(const std::string basePath, const std::string tokenDir, const ByteString& label, const ByteString& serial);
+
+       // Access an existing token
+       static ObjectStoreToken* accessToken(const std::string &basePath, const std::string &tokenDir);
+
+       // Set the SO PIN
+       virtual bool setSOPIN(const ByteString& soPINBlob) = 0;
+
+       // Get the SO PIN
+       virtual bool getSOPIN(ByteString& soPINBlob) = 0;
+
+       // Set the user PIN
+       virtual bool setUserPIN(ByteString userPINBlob) = 0;
+
+       // Get the user PIN
+       virtual bool getUserPIN(ByteString& userPINBlob) = 0;
+
+       // Get the token flags
+       virtual bool getTokenFlags(CK_ULONG& flags) = 0;
+
+       // Set the token flags
+       virtual bool setTokenFlags(const CK_ULONG flags) = 0;
+
+       // Retrieve the token label
+       virtual bool getTokenLabel(ByteString& label) = 0;
+
+       // Retrieve the token serial
+       virtual bool getTokenSerial(ByteString& serial) = 0;
+
+       // Retrieve objects
+       virtual std::set<OSObject*> getObjects() = 0;
+
+       // Insert objects into the given set
+       virtual void getObjects(std::set<OSObject*> &objects) = 0;
+
+       // Create a new object
+       virtual OSObject* createObject() = 0;
+
+       // Delete an object
+       virtual bool deleteObject(OSObject* object) = 0;
+
+       // Destructor
+       virtual ~ObjectStoreToken() {};
+
+       // Checks if the token is consistent
+       virtual bool isValid() = 0;
+
+       // Invalidate the token (for instance if it is deleted)
+       virtual void invalidate() = 0;
+
+       // Delete the token
+       virtual bool clearToken() = 0;
+
+       // Reset the token
+       virtual bool resetToken(const ByteString& label) = 0;
+};
+
+#endif // !_SOFTHSM_V2_OBJECTSTORETOKEN_H
+
diff --git a/SoftHSMv2/src/lib/object_store/SessionObject.cpp b/SoftHSMv2/src/lib/object_store/SessionObject.cpp
new file mode 100644 (file)
index 0000000..49dfa7d
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionObject.cpp
+
+ This class implements session objects (i.e. objects that are non-persistent)
+ *****************************************************************************/
+
+#include "config.h"
+#include "SessionObject.h"
+#include "SessionObjectStore.h"
+
+// Constructor
+SessionObject::SessionObject(SessionObjectStore* inParent, CK_SLOT_ID inSlotID, CK_SESSION_HANDLE inHSession, bool inIsPrivate)
+{
+       hSession = inHSession;
+       slotID = inSlotID;
+       isPrivate = inIsPrivate;
+       objectMutex = MutexFactory::i()->getMutex();
+       valid = (objectMutex != NULL);
+       parent = inParent;
+}
+
+// Destructor
+SessionObject::~SessionObject()
+{
+       discardAttributes();
+
+       MutexFactory::i()->recycleMutex(objectMutex);
+}
+
+// Check if the specified attribute exists
+bool SessionObject::attributeExists(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       return valid && (attributes[type] != NULL);
+}
+
+// Retrieve the specified attribute
+OSAttribute SessionObject::getAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return OSAttribute((unsigned long)0);
+       }
+
+       return *attr;
+}
+
+bool SessionObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isBooleanAttribute())
+       {
+               return attr->getBooleanValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
+               return val;
+       }
+}
+
+unsigned long SessionObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
+{
+       MutexLocker lock(objectMutex);
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isUnsignedLongAttribute())
+       {
+               return attr->getUnsignedLongValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
+               return val;
+       }
+}
+
+ByteString SessionObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       ByteString val;
+
+       OSAttribute* attr = attributes[type];
+       if (attr == NULL)
+       {
+               ERROR_MSG("The attribute does not exist: 0x%08X", type);
+               return val;
+       }
+
+       if (attr->isByteStringAttribute())
+       {
+               return attr->getByteStringValue();
+       }
+       else
+       {
+               ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
+               return val;
+       }
+}
+
+// Retrieve the next attribute type
+CK_ATTRIBUTE_TYPE SessionObject::nextAttributeType(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*>::iterator n = attributes.upper_bound(type);
+
+       // skip null attributes
+       while ((n != attributes.end()) && (n->second == NULL))
+               ++n;
+
+
+       // return type or CKA_CLASS (= 0)
+       if (n == attributes.end())
+       {
+               return CKA_CLASS;
+       }
+       else
+       {
+               return n->first;
+       }
+}
+
+// Set the specified attribute
+bool SessionObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
+{
+       MutexLocker lock(objectMutex);
+
+       if (!valid)
+       {
+               DEBUG_MSG("Cannot update invalid session object 0x%08X", this);
+
+               return false;
+       }
+
+       if (attributes[type] != NULL)
+       {
+               delete attributes[type];
+
+               attributes[type] = NULL;
+       }
+
+       attributes[type] = new OSAttribute(attribute);
+
+       return true;
+}
+
+// Delete the specified attribute
+bool SessionObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
+{
+       MutexLocker lock(objectMutex);
+
+       if (!valid)
+       {
+               DEBUG_MSG("Cannot update invalid session object 0x%08X", this);
+
+               return false;
+       }
+
+       if (attributes[type] == NULL)
+       {
+               DEBUG_MSG("Cannot delete attribute that doesn't exist in object 0x%08X", this);
+
+               return false;
+       }
+
+       delete attributes[type];
+       attributes.erase(type);
+
+       return true;
+}
+
+// The validity state of the object
+bool SessionObject::isValid()
+{
+    return valid;
+}
+
+bool SessionObject::hasSlotID(CK_SLOT_ID inSlotID)
+{
+    return slotID == inSlotID;
+}
+
+// Called by the session object store when a session is closed. If it's the
+// session this object was associated with, the function returns true and the
+// object is invalidated
+bool SessionObject::removeOnSessionClose(CK_SESSION_HANDLE inHSession)
+{
+       if (hSession == inHSession)
+       {
+               // Save space
+               discardAttributes();
+
+               valid = false;
+
+               return true;
+       }
+
+       return false;
+}
+
+// Called by the session object store when a token is logged out.
+// Remove when this session object is a private object for this token.
+bool SessionObject::removeOnAllSessionsClose(CK_SLOT_ID inSlotID)
+{
+    if (slotID == inSlotID)
+    {
+        discardAttributes();
+
+        valid = false;
+
+        return true;
+    }
+
+    return false;
+}
+
+// Called by the session object store when a token is logged out.
+// Remove when this session object is a private object for this token.
+bool SessionObject::removeOnTokenLogout(CK_SLOT_ID inSlotID)
+{
+    if (slotID == inSlotID && isPrivate)
+    {
+        discardAttributes();
+
+        valid = false;
+
+        return true;
+    }
+
+    return false;
+}
+
+// Discard the object's attributes
+void SessionObject::discardAttributes()
+{
+       MutexLocker lock(objectMutex);
+
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*> cleanUp = attributes;
+       attributes.clear();
+
+       for (std::map<CK_ATTRIBUTE_TYPE, OSAttribute*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               if (i->second == NULL)
+               {
+                       continue;
+               }
+
+               delete i->second;
+               i->second = NULL;
+       }
+}
+
+// These functions are just stubs for session objects
+bool SessionObject::startTransaction(Access)
+{
+       return true;
+}
+
+bool SessionObject::commitTransaction()
+{
+       return true;
+}
+
+bool SessionObject::abortTransaction()
+{
+       return true;
+}
+
+bool SessionObject::destroyObject()
+{
+       if (parent == NULL)
+       {
+               ERROR_MSG("Cannot destroy object that is not associated with a session object store");
+
+               return false;
+       }
+
+       return parent->deleteObject(this);
+}
+
+// Invalidate the object
+void SessionObject::invalidate()
+{
+       valid = false;
+       discardAttributes();
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/SessionObject.h b/SoftHSMv2/src/lib/object_store/SessionObject.h
new file mode 100644 (file)
index 0000000..caadb64
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionObject.h
+
+ This class implements session objects (i.e. objects that are non-persistent)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONOBJECT_H
+#define _SOFTHSM_V2_SESSIONOBJECT_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "OSAttribute.h"
+#include "MutexFactory.h"
+#include <string>
+#include <map>
+#include "cryptoki.h"
+#include "OSObject.h"
+
+// Forward declaration of the session object store
+class SessionObjectStore;
+
+class SessionObject : public OSObject
+{
+public:
+       // Constructor
+       SessionObject(SessionObjectStore* inParent, CK_SLOT_ID inSlotID, CK_SESSION_HANDLE inHSession, bool inIsPrivate = false);
+
+       // Destructor
+       virtual ~SessionObject();
+
+       // Check if the specified attribute exists
+       virtual bool attributeExists(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the specified attribute
+       virtual OSAttribute getAttribute(CK_ATTRIBUTE_TYPE type);
+       virtual bool getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val);
+       virtual unsigned long getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val);
+       virtual ByteString getByteStringValue(CK_ATTRIBUTE_TYPE type);
+
+       // Retrieve the next attribute type
+       virtual CK_ATTRIBUTE_TYPE nextAttributeType(CK_ATTRIBUTE_TYPE type);
+
+       // Set the specified attribute
+       virtual bool setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute);
+
+       // Delete the specified attribute
+       virtual bool deleteAttribute(CK_ATTRIBUTE_TYPE type);
+
+       // The validity state of the object
+       virtual bool isValid();
+
+       bool hasSlotID(CK_SLOT_ID inSlotID);
+
+       // Called by the session object store when a session is closed. If it's the
+       // session this object was associated with, the function returns true and the
+       // object is invalidated
+       bool removeOnSessionClose(CK_SESSION_HANDLE inHSession);
+
+       // Called by the session object store when all the sessions for a token
+       // have been closed.
+       bool removeOnAllSessionsClose(CK_SLOT_ID inSlotID);
+
+       // Called by the session object store when a token is logged out.
+       // Remove when this session object is a private object for this token.
+       bool removeOnTokenLogout(CK_SLOT_ID inSlotID);
+
+       // These functions are just stubs for session objects
+       virtual bool startTransaction(Access access);
+       virtual bool commitTransaction();
+       virtual bool abortTransaction();
+
+       // Destroys the object; WARNING: pointers to the object become invalid after this
+       // call!
+       virtual bool destroyObject();
+
+       // Invalidate the object
+       void invalidate();
+
+private:
+       // Discard the object's attributes
+       void discardAttributes();
+
+       // The object's raw attributes
+       std::map<CK_ATTRIBUTE_TYPE, OSAttribute*> attributes;
+
+       // The object's validity state
+       bool valid;
+
+       // Mutex object for thread-safeness
+       Mutex* objectMutex;
+
+       // The slotID of the object is associated with.
+       CK_SLOT_ID slotID;
+
+       // The session the object is associated with.
+       CK_SESSION_HANDLE hSession;
+
+       // Indicates whether this object is private
+       bool isPrivate;
+
+       // The parent SessionObjectStore
+       SessionObjectStore* parent;
+};
+
+#endif // !_SOFTHSM_V2_SESSIONOBJECT_H
+
diff --git a/SoftHSMv2/src/lib/object_store/SessionObjectStore.cpp b/SoftHSMv2/src/lib/object_store/SessionObjectStore.cpp
new file mode 100644 (file)
index 0000000..3370d20
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionObjectStore.cpp
+
+ The token class; a token is stored in a directory containing several files.
+ Each object is stored in a separate file and a token object is present that
+ has the token specific attributes
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSAttributes.h"
+#include "OSAttribute.h"
+#include "SessionObject.h"
+#include "cryptoki.h"
+#include "SessionObjectStore.h"
+#include <vector>
+#include <string>
+#include <set>
+#include <map>
+#include <list>
+
+// Constructor
+SessionObjectStore::SessionObjectStore()
+{
+       storeMutex = MutexFactory::i()->getMutex();
+}
+
+// Destructor
+SessionObjectStore::~SessionObjectStore()
+{
+       // Clean up
+       objects.clear();
+       std::set<SessionObject*> cleanUp = allObjects;
+       allObjects.clear();
+
+       for (std::set<SessionObject*>::iterator i = cleanUp.begin(); i != cleanUp.end(); i++)
+       {
+               if ((*i) == NULL) continue;
+
+               SessionObject* that = *i;
+               delete that;
+       }
+
+       MutexFactory::i()->recycleMutex(storeMutex);
+}
+
+// Retrieve objects
+std::set<SessionObject*> SessionObjectStore::getObjects()
+{
+       // Make sure that no other thread is in the process of changing
+       // the object list when we return it
+       MutexLocker lock(storeMutex);
+
+       return objects;
+}
+
+void SessionObjectStore::getObjects(CK_SLOT_ID slotID, std::set<OSObject*> &inObjects)
+{
+       // Make sure that no other thread is in the process of changing
+       // the object list when we return it
+       MutexLocker lock(storeMutex);
+
+       std::set<SessionObject*>::iterator it;
+       for (it=objects.begin(); it!=objects.end(); ++it) {
+               if ((*it)->hasSlotID(slotID))
+                       inObjects.insert(*it);
+       }
+}
+
+// Create a new object
+SessionObject* SessionObjectStore::createObject(CK_SLOT_ID slotID, CK_SESSION_HANDLE hSession, bool isPrivate)
+{
+       // Create the new object file
+       SessionObject* newObject = new SessionObject(this, slotID, hSession, isPrivate);
+
+       if (!newObject->isValid())
+       {
+               ERROR_MSG("Failed to create new object");
+
+               delete newObject;
+
+               return NULL;
+       }
+
+       // Now add it to the set of objects
+       MutexLocker lock(storeMutex);
+
+       objects.insert(newObject);
+       allObjects.insert(newObject);
+
+       DEBUG_MSG("(0x%08X) Created new object (0x%08X)", this, newObject);
+
+       return newObject;
+}
+
+// Delete an object
+bool SessionObjectStore::deleteObject(SessionObject* object)
+{
+       if (objects.find(object) == objects.end())
+       {
+               ERROR_MSG("Cannot delete non-existent object 0x%08X", object);
+
+               return false;
+       }
+
+       MutexLocker lock(storeMutex);
+
+       // Invalidate the object instance
+       object->invalidate();
+
+       objects.erase(object);
+
+       return true;
+}
+
+// Indicate that a session has been closed; invalidates all objects
+// associated with this session
+void SessionObjectStore::sessionClosed(CK_SESSION_HANDLE hSession)
+{
+       MutexLocker lock(storeMutex);
+
+       std::set<SessionObject*> checkObjects = objects;
+
+       for (std::set<SessionObject*>::iterator i = checkObjects.begin(); i != checkObjects.end(); i++)
+       {
+        if ((*i)->removeOnSessionClose(hSession))
+               {
+                       // Since the object remains in the allObjects set, any pointers to it will
+                       // remain valid but it will no longer be returned when the set of objects
+                       // is requested
+                       objects.erase(*i);
+               }
+    }
+}
+
+void SessionObjectStore::allSessionsClosed(CK_SLOT_ID slotID)
+{
+       MutexLocker lock(storeMutex);
+
+       std::set<SessionObject*> checkObjects = objects;
+
+       for (std::set<SessionObject*>::iterator i = checkObjects.begin(); i != checkObjects.end(); i++)
+       {
+               if ((*i)->removeOnAllSessionsClose(slotID))
+               {
+                       // Since the object remains in the allObjects set, any pointers to it will
+                       // remain valid but it will no longer be returned when the set of objects
+                       // is requested
+                       objects.erase(*i);
+               }
+       }
+}
+
+void SessionObjectStore::tokenLoggedOut(CK_SLOT_ID slotID)
+{
+       MutexLocker lock(storeMutex);
+
+       std::set<SessionObject*> checkObjects = objects;
+
+       for (std::set<SessionObject*>::iterator i = checkObjects.begin(); i != checkObjects.end(); i++)
+       {
+               if ((*i)->removeOnTokenLogout(slotID))
+               {
+                       // Since the object remains in the allObjects set, any pointers to it will
+                       // remain valid but it will no longer be returned when the set of objects
+                       // is requested
+                       objects.erase(*i);
+               }
+       }
+}
+
+// Clear the whole store
+void SessionObjectStore::clearStore()
+{
+       MutexLocker lock(storeMutex);
+
+       objects.clear();
+       std::set<SessionObject*> clearObjects = allObjects;
+       allObjects.clear();
+
+       for (std::set<SessionObject*>::iterator i = clearObjects.begin(); i != clearObjects.end(); i++)
+       {
+               delete *i;
+       }
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/SessionObjectStore.h b/SoftHSMv2/src/lib/object_store/SessionObjectStore.h
new file mode 100644 (file)
index 0000000..2ec4bc5
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionObjectStore.h
+
+ The token class; a token is stored in a directory containing several files.
+ Each object is stored in a separate file and a token object is present that
+ has the token specific attributes
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONOBJECTSTORE_H
+#define _SOFTHSM_V2_SESSIONOBJECTSTORE_H
+
+#include "config.h"
+#include "OSAttribute.h"
+#include "SessionObject.h"
+#include "MutexFactory.h"
+#include "cryptoki.h"
+#include <string>
+#include <set>
+#include <map>
+#include <list>
+#include <memory>
+
+class SessionObjectStore
+{
+public:
+       // Constructor
+       SessionObjectStore();
+
+       // Retrieve objects
+       std::set<SessionObject*> getObjects();
+
+       // Insert the session objects for the given slotID into the given OSObject set
+       void getObjects(CK_SLOT_ID slotID, std::set<OSObject*> &inObjects);
+
+       // Create a new object
+       SessionObject* createObject(CK_SLOT_ID slotID, CK_SESSION_HANDLE hSession, bool isPrivate = false);
+
+       // Delete an object
+       bool deleteObject(SessionObject* object);
+
+       // Indicate that a session has been closed; invalidates all objects
+       // associated with this session.
+       void sessionClosed(CK_SESSION_HANDLE hSession);
+
+       // Indicate that for a token all sessions have been closed.
+       // Invalidates all objects associated with the token.
+       void allSessionsClosed(CK_SLOT_ID slotID);
+
+       // Indicate that a token has been logged out; invalidates all private
+       // objects associated with this token.
+       void tokenLoggedOut(CK_SLOT_ID slotID);
+
+       // Destructor
+       virtual ~SessionObjectStore();
+
+       // Clears the store; should be called when all sessions are closed
+       void clearStore();
+
+private:
+       // The current objects in the store
+       std::set<SessionObject*> objects;
+
+       // All the objects ever kept in the store
+       std::set<SessionObject*> allObjects;
+
+       // The current list of files
+       std::set<std::string> currentFiles;
+
+       // For thread safeness
+       Mutex* storeMutex;
+};
+
+#endif // !_SOFTHSM_V2_SESSIONOBJECTSTORE_H
+
diff --git a/SoftHSMv2/src/lib/object_store/UUID.cpp b/SoftHSMv2/src/lib/object_store/UUID.cpp
new file mode 100644 (file)
index 0000000..9e9f541
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ UUID.cpp
+
+ UUID generation helper functions
+ *****************************************************************************/
+
+#include "config.h"
+#include "UUID.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+// Generate a new UUID string
+std::string UUID::newUUID()
+{
+       RNG* rng = CryptoFactory::i()->getRNG();
+
+       ByteString uuid;
+
+       if (!rng->generateRandom(uuid, 16))
+       {
+               ERROR_MSG("Fatal, could not generate random UUID");
+
+               throw -1;
+       }
+
+       // Convert it to a string
+       char uuidStr[37];
+
+       sprintf(uuidStr, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+               uuid[0], uuid[1], uuid[2], uuid[3], 
+               uuid[4], uuid[5], 
+               uuid[6], uuid[7],
+               uuid[8], uuid[9],
+               uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+
+       return std::string(uuidStr);
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/UUID.h b/SoftHSMv2/src/lib/object_store/UUID.h
new file mode 100644 (file)
index 0000000..569bc00
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ UUID.h
+
+ UUID generation helper functions; for now, this just wraps the OSF/DCE's
+ UUID generation implementation, but if SoftHSM gets ported to non UNIX/BSD-
+ like OSes this may incorporate other implementations
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_UUID_H
+#define _SOFTHSM_V2_UUID_H
+
+#include "config.h"
+#include <string>
+
+namespace UUID
+{
+       // Generate a new UUID string
+       std::string newUUID();
+};
+
+#endif // !_SOFTHSM_V2_UUID_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp
new file mode 100644 (file)
index 0000000..2cc8360
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObjectStoreTests.cpp
+
+ Contains test cases to test the object store implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DBObjectStoreTests.h"
+
+#include <cstdio>
+
+#ifndef HAVE_SQLITE3_H
+#error expected sqlite3 to be available
+#endif
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store);
+
+void test_a_newly_created_object_store::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+
+       ObjectStoreToken::selectBackend("db");
+
+       store = new ObjectStore("testdir");
+       nulltoken = NULL;
+}
+
+void test_a_newly_created_object_store::tearDown()
+{
+       delete store;
+
+       ObjectStoreToken::selectBackend("file");
+
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+
+void test_a_newly_created_object_store::contains_no_items()
+{
+       CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)0);
+}
+
+void test_a_newly_created_object_store::can_create_a_new_token()
+{
+       ByteString label1 = "DEADC0FFEE";
+
+       ObjectStoreToken *token1 = store->newToken(label1);
+       CPPUNIT_ASSERT(token1 != nulltoken);
+       CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store_containing_two_tokens);
+
+
+void test_a_newly_created_object_store_containing_two_tokens::setUp()
+{
+       test_a_newly_created_object_store::setUp();
+
+       ByteString label1 = "DEADC0FFEE";
+       ByteString label2 = "DEADBEEF";
+
+       ObjectStoreToken* token1 = store->newToken(label1);
+       CPPUNIT_ASSERT(token1 != nulltoken);
+       CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1);
+
+       ObjectStoreToken* token2 = store->newToken(label2);
+       CPPUNIT_ASSERT(token2 != nulltoken);
+       CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2);
+}
+
+void test_a_newly_created_object_store_containing_two_tokens::tearDown()
+{
+       ObjectStoreToken* token1 = store->getToken(0);
+       ObjectStoreToken* token2 = store->getToken(1);
+       CPPUNIT_ASSERT(store->destroyToken(token1));
+       CPPUNIT_ASSERT(store->destroyToken(token2));
+
+       test_a_newly_created_object_store::tearDown();
+}
+
+void test_a_newly_created_object_store_containing_two_tokens::has_two_tokens()
+{
+       CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2);
+}
+
+void test_a_newly_created_object_store_containing_two_tokens::can_access_both_tokens()
+{
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* token1 = store->getToken(0);
+       ObjectStoreToken* token2 = store->getToken(1);
+
+       CPPUNIT_ASSERT(token1 != nulltoken);
+       CPPUNIT_ASSERT(token2 != nulltoken);
+}
+
+void test_a_newly_created_object_store_containing_two_tokens::assigned_labels_correctly_to_tokens()
+{
+       ByteString label1 = "DEADC0FFEE";
+       ByteString label2 = "DEADBEEF";
+
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* token1 = store->getToken(0);
+       ObjectStoreToken* token2 = store->getToken(1);
+
+       ByteString retrieveLabel1, retrieveLabel2;
+
+       CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1));
+       CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2));
+
+       CPPUNIT_ASSERT(label1 == retrieveLabel1 || label1 == retrieveLabel2);
+       CPPUNIT_ASSERT(label2 == retrieveLabel1 || label2 == retrieveLabel2);
+       CPPUNIT_ASSERT(label1 != label2);
+}
+
+void test_a_newly_created_object_store_containing_two_tokens::assigned_a_unique_serial_number_to_each_token()
+{
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* token1 = store->getToken(0);
+       ObjectStoreToken* token2 = store->getToken(1);
+
+       ByteString retrieveSerial1, retrieveSerial2;
+
+       CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1));
+       CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2));
+
+       CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2);
+}
diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h
new file mode 100644 (file)
index 0000000..7d100c8
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObjectStoreTests.h
+
+ Contains test cases to test the object store implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBOBJECTSTORETESTS_H
+#define _SOFTHSM_V2_DBOBJECTSTORETESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "ObjectStore.h"
+#include "ObjectStoreToken.h"
+
+class test_a_newly_created_object_store : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(test_a_newly_created_object_store);
+       CPPUNIT_TEST(contains_no_items);
+       CPPUNIT_TEST(can_create_a_new_token);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void contains_no_items();
+       void can_create_a_new_token();
+protected:
+       ObjectStore *store;
+       ObjectStoreToken *nulltoken;
+
+private:
+};
+
+class test_a_newly_created_object_store_containing_two_tokens : public test_a_newly_created_object_store
+{
+       CPPUNIT_TEST_SUITE(test_a_newly_created_object_store_containing_two_tokens);
+       CPPUNIT_TEST(has_two_tokens);
+       CPPUNIT_TEST(can_access_both_tokens);
+       CPPUNIT_TEST(assigned_labels_correctly_to_tokens);
+       CPPUNIT_TEST(assigned_a_unique_serial_number_to_each_token);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void has_two_tokens();
+       void can_access_both_tokens();
+       void assigned_labels_correctly_to_tokens();
+       void assigned_a_unique_serial_number_to_each_token();
+};
+
+#endif // !_SOFTHSM_V2_DBOBJECTSTORETESTS_H
diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp
new file mode 100644 (file)
index 0000000..d856b06
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObjectTests.cpp
+
+ Contains test cases to test the database token object implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DBObjectTests.h"
+#include "DBObject.h"
+
+#include <cstdio>
+
+#ifndef HAVE_SQLITE3_H
+#error expected sqlite3 to be available
+#endif
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbobject);
+
+void test_a_dbobject::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+       connection = DB::Connection::Create("testdir","TestToken");
+       CPPUNIT_ASSERT(connection != NULL);
+       CPPUNIT_ASSERT(connection->connect("<1>"));
+       connection->setBusyTimeout(10);
+
+       DBObject testObject(connection);
+       CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite));
+       CPPUNIT_ASSERT(testObject.createTables());
+       CPPUNIT_ASSERT(testObject.commitTransaction());
+
+       connection2 = DB::Connection::Create("testdir","TestToken");
+       CPPUNIT_ASSERT(connection2 != NULL);
+       CPPUNIT_ASSERT(connection2->connect("<2>"));
+       connection2->setBusyTimeout(10);
+}
+
+void test_a_dbobject::tearDown()
+{
+       CPPUNIT_ASSERT(connection != NULL);
+       connection->close();
+       delete connection;
+
+       CPPUNIT_ASSERT(connection2 != NULL);
+       connection2->close();
+       delete connection2;
+
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void test_a_dbobject::should_be_insertable()
+{
+       DBObject tokenObject(connection);
+       CPPUNIT_ASSERT(!tokenObject.isValid());
+       CPPUNIT_ASSERT(tokenObject.insert());
+       CPPUNIT_ASSERT(tokenObject.isValid());
+       CPPUNIT_ASSERT_EQUAL(tokenObject.objectId(), (long long)1);
+}
+
+void test_a_dbobject::should_be_selectable()
+{
+       should_be_insertable();
+
+       DBObject tokenObject(connection);
+       CPPUNIT_ASSERT(tokenObject.find(1));
+       CPPUNIT_ASSERT(tokenObject.isValid());
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbobject_with_an_object);
+
+void test_a_dbobject_with_an_object::setUp()
+{
+       test_a_dbobject::setUp();
+       DBObject tokenObject(connection);
+       CPPUNIT_ASSERT(tokenObject.startTransaction(DBObject::ReadWrite));
+       CPPUNIT_ASSERT(!tokenObject.isValid());
+       CPPUNIT_ASSERT(tokenObject.insert());
+       CPPUNIT_ASSERT(tokenObject.isValid());
+       CPPUNIT_ASSERT_EQUAL(tokenObject.objectId(), (long long)1);
+       CPPUNIT_ASSERT(tokenObject.commitTransaction());
+
+}
+
+void test_a_dbobject_with_an_object::tearDown()
+{
+       test_a_dbobject::tearDown();
+}
+
+void test_a_dbobject_with_an_object::should_store_boolean_attributes()
+{
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               bool value2 = false;
+               bool value3 = true;
+               bool value4 = true;
+               bool value5 = false;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5));
+       }
+
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue());
+               CPPUNIT_ASSERT(!testObject.getAttribute(CKA_SENSITIVE).getBooleanValue());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue());
+               CPPUNIT_ASSERT(!testObject.getAttribute(CKA_SIGN).getBooleanValue());
+
+               bool value6 = true;
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute());
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_VERIFY).getBooleanValue(), value6);
+               CPPUNIT_ASSERT_EQUAL(testObject.getBooleanValue(CKA_VERIFY, false), value6);
+       }
+}
+
+
+void test_a_dbobject_with_an_object::should_store_unsigned_long_attributes()
+{
+       // Add unsigned long attributes to the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               unsigned long value1 = 0x12345678;
+               unsigned long value2 = 0x87654321;
+               unsigned long value3 = 0x01010101;
+               unsigned long value4 = 0x10101010;
+               unsigned long value5 = 0xABCDEF;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute());
+
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue(), (unsigned long)0x12345678);
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue(), (unsigned long)0x87654321);
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue(), (unsigned long)0x01010101);
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue(), (unsigned long)0x10101010);
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue(), (unsigned long)0xABCDEF);
+
+               unsigned long value6 = 0x90909090;
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue(), value6);
+               CPPUNIT_ASSERT_EQUAL(testObject.getUnsignedLongValue(CKA_CLASS, 0x0), value6);
+       }
+}
+
+void test_a_dbobject_with_an_object::should_store_binary_attributes()
+{
+       ByteString value1 = "010203040506070809";
+       ByteString value2 = "ABABABABABABABABABABABABABABABABAB";
+       unsigned long value3 = 0xBDED;
+       ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7";
+       ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD";
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5);
+
+               ByteString value6 = "909090908080808080807070707070FF";
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6);
+       }
+}
+
+void test_a_dbobject_with_an_object::should_store_mechtypeset_attributes()
+{
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               std::set<CK_MECHANISM_TYPE> set;
+               set.insert(CKM_SHA256);
+               set.insert(CKM_SHA512);
+               OSAttribute attr(set);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               std::set<CK_MECHANISM_TYPE> retrieved =
+                               testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue();
+
+               CPPUNIT_ASSERT(retrieved.size() == 2);
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end());
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end());
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end());
+       }
+}
+
+void test_a_dbobject_with_an_object::should_store_attrmap_attributes()
+{
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr;
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE, attr3));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_ALLOWED_MECHANISMS, attr4));
+               OSAttribute attra(mattr);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE));
+
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb =
+                               testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue();
+               CPPUNIT_ASSERT(mattrb.size() == 4);
+               CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(mattrb.find(CKA_VALUE) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(mattrb.find(CKA_ALLOWED_MECHANISMS) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+       }
+}
+
+void test_a_dbobject_with_an_object::should_store_mixed_attributes()
+{
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+       unsigned long value3 = 0xBDEBDBED;
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue());
+               CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue(), value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+       }
+}
+
+void test_a_dbobject_with_an_object::should_store_double_attributes()
+{
+       bool value1 = true;
+       bool value1a = false;
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue());
+
+               OSAttribute attr1(value1a);
+
+               // Change the attributes
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1));
+
+               // Check the attributes
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a);
+       }
+
+       // Now re-read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a);
+       }
+}
+
+void test_a_dbobject_with_an_object::can_refresh_attributes()
+{
+       bool value1 = true;
+       bool value1a = false;
+       ByteString value2 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value2a = "466487346943785684957634";
+       ByteString value3 = "0102010201020102010201020102010201020102";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+       std::set<CK_MECHANISM_TYPE> value4a;
+       value4a.insert(CKM_SHA384);
+       value4a.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr4(value4);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+       }
+
+       // Now read back the object
+       {
+               DBObject testObject(connection);
+               CPPUNIT_ASSERT(testObject.find(1));
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+               OSAttribute attr1(value1a);
+               OSAttribute attr2(value2a);
+               OSAttribute attr4(value4a);
+
+               // Change the attributes
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+
+               // Check the attributes
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value2a);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+               // Open the object a second time
+               DBObject testObject2(connection);
+               CPPUNIT_ASSERT(testObject2.find(1));
+               CPPUNIT_ASSERT(testObject2.isValid());
+
+               // Check the attributes on the second instance
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SIGN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SIGN).getBooleanValue() == value1a);
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SUBJECT).getByteStringValue() == value2a);
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+               // Add an attribute on the second object
+               OSAttribute attr3(value3);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr3));
+
+               // Check the attribute
+               CPPUNIT_ASSERT(testObject2.attributeExists(CKA_ID));
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value3);
+
+               // Now check that the first instance also knows about it
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ID));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value3);
+       }
+}
+
+void test_a_dbobject_with_an_object::should_cleanup_statements_during_transactions()
+{
+       // Create an object for accessing object 1 on the first connection.
+       DBObject testObject(connection);
+       // check transaction start(ro)/abort sequence
+       CPPUNIT_ASSERT(testObject.startTransaction(OSObject::ReadOnly));
+       CPPUNIT_ASSERT(testObject.find(1));
+       CPPUNIT_ASSERT(testObject.isValid());
+       CPPUNIT_ASSERT(testObject.abortTransaction());
+}
+
+void test_a_dbobject_with_an_object::should_use_transactions()
+{
+       DBObject testObject(connection);
+       CPPUNIT_ASSERT(testObject.find(1));
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+       unsigned long value3 = 0xBDEBDBED;
+       ByteString value4 = "AAAAAAAAAAAAAAAFFFFFFFFFFFFFFF";
+       std::set<CK_MECHANISM_TYPE> value5;
+       value5.insert(CKM_SHA256);
+       value5.insert(CKM_SHA512);
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+       OSAttribute attr4(value4);
+       OSAttribute attr5(value5);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5));
+
+       // Create secondary instance for the same object.
+       // This needs to have a different connection to the database to simulate
+       // another process accessing the data.
+       DBObject testObject2(connection2);
+       CPPUNIT_ASSERT(testObject2.find(1));
+       CPPUNIT_ASSERT(testObject2.isValid());
+
+       // Check that it has the same attributes
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       // Check that the attributes have the same values as set on testObject.
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5);
+
+       // New values
+       bool value1a = false;
+       unsigned long value2a = 0x12345678;
+       unsigned long value3a = 0xABABABAB;
+       ByteString value4a = "EDEDEDEDEDEDEDEDEDEDEDEDEDEDED";
+       std::set<CK_MECHANISM_TYPE> value5a;
+       value5a.insert(CKM_SHA384);
+       value5a.insert(CKM_SHA512);
+
+       OSAttribute attr1a(value1a);
+       OSAttribute attr2a(value2a);
+       OSAttribute attr3a(value3a);
+       OSAttribute attr4a(value4a);
+       OSAttribute attr5a(value5a);
+
+       // Start transaction on object
+       CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite));
+
+       // Change the attributes
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5a));
+
+       // Verify that the attributes were set
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a);
+
+       // Verify that they are unchanged on the other instance
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5);
+
+       // Commit the transaction
+       CPPUNIT_ASSERT(testObject.commitTransaction());
+
+       // Verify that non-modifiable attributes did not propagate but modifiable attributes
+       // have now changed on the other instance
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       // NOTE: 3 attributes below cannot be modified after creation and therefore are not required to propagate.
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() != value1a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() != value2a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() != value3a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() != value5a);
+
+       // CKA_ID attribute can be modified after creation and therefore should have propagated.
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4a);
+
+       // Start transaction on object
+       CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite));
+
+       // Change the attributes
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5));
+
+       // Verify that the attributes were set
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5);
+
+       // Create a fresh third instance for the same object to force the data to be retrieved from the database.
+       DBObject testObject3(connection2);
+       CPPUNIT_ASSERT(testObject3.find(1));
+       CPPUNIT_ASSERT(testObject3.isValid());
+
+       // Verify that they are unchanged on the other instance, while the transaction is still in progress.
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       // Verify that the attributes from the database are still hodling the same value as when the transaction started.
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a);
+
+       // Abort the transaction
+       CPPUNIT_ASSERT(testObject.abortTransaction());
+
+       // Verify that after aborting the transaction the values in testObject have reverted back to their
+       // original state.
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       // After aborting a transaction the testObject should be back to pre transaction state.
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a);
+
+       // Verify that testObject3 still has the original values.
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       // Verify that testObject3 still has the original values.
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a);
+       CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a);
+}
+
+void test_a_dbobject_with_an_object::should_fail_to_delete()
+{
+       DBObject testObject(connection);
+       CPPUNIT_ASSERT(testObject.find(1));
+       CPPUNIT_ASSERT(testObject.isValid());
+       // We don't attach the object to a token, and therefore should not be able to destroy it.
+       CPPUNIT_ASSERT(!testObject.destroyObject());
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h
new file mode 100644 (file)
index 0000000..136fa81
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBObjectTests.h
+
+ Contains test cases to test the database token object implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBOBJECTTESTS_H
+#define _SOFTHSM_V2_DBOBJECTTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "DB.h"
+
+class test_a_dbobject : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(test_a_dbobject);
+       CPPUNIT_TEST(should_be_insertable);
+       CPPUNIT_TEST(should_be_selectable);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void should_be_insertable();
+       void should_be_selectable();
+
+protected:
+       DB::Connection *connection;
+       DB::Connection *connection2;
+
+private:
+};
+
+class test_a_dbobject_with_an_object : public test_a_dbobject
+{
+       CPPUNIT_TEST_SUITE(test_a_dbobject_with_an_object);
+       CPPUNIT_TEST(should_store_boolean_attributes);
+       CPPUNIT_TEST(should_store_unsigned_long_attributes);
+       CPPUNIT_TEST(should_store_binary_attributes);
+       CPPUNIT_TEST(should_store_mechtypeset_attributes);
+       CPPUNIT_TEST(should_store_attrmap_attributes);
+       CPPUNIT_TEST(should_store_mixed_attributes);
+       CPPUNIT_TEST(should_store_double_attributes);
+       CPPUNIT_TEST(can_refresh_attributes);
+       CPPUNIT_TEST(should_cleanup_statements_during_transactions);
+       CPPUNIT_TEST(should_use_transactions);
+       CPPUNIT_TEST(should_fail_to_delete);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void should_store_boolean_attributes();
+       void should_store_unsigned_long_attributes();
+       void should_store_binary_attributes();
+    void should_store_mechtypeset_attributes();
+       void should_store_attrmap_attributes();
+       void should_store_mixed_attributes();
+       void should_store_double_attributes();
+       void can_refresh_attributes();
+       void should_cleanup_statements_during_transactions();
+       void should_use_transactions();
+       void should_fail_to_delete();
+};
+
+#endif // !_SOFTHSM_V2_DBOBJECTTESTS_H
diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp
new file mode 100644 (file)
index 0000000..d787a83
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBTests.cpp
+
+ Contains lowest level test cases for the database backend implementation.
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DBTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db);
+
+static int dummy_print(const char *, va_list )
+{
+       return 0;
+}
+
+void test_a_db::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+       null = NULL;
+}
+
+void test_a_db::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void test_a_db::checks_for_empty_connection_parameters()
+{
+       DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print);
+
+       DB::Connection *connection = DB::Connection::Create("","TestToken");
+       CPPUNIT_ASSERT_EQUAL(connection, null);
+
+       connection = DB::Connection::Create("testdir","");
+       CPPUNIT_ASSERT_EQUAL(connection, null);
+
+       connection = DB::Connection::Create("","");
+       CPPUNIT_ASSERT_EQUAL(connection, null);
+
+       DB::setLogErrorHandler(eh);
+}
+
+void test_a_db::can_be_connected_to_database()
+{
+
+       DB::Connection *connection = DB::Connection::Create("testdir","TestToken");
+       CPPUNIT_ASSERT(connection != null);
+       bool isConnected = connection->connect();
+       delete connection;
+       CPPUNIT_ASSERT(isConnected);
+#ifndef _WIN32
+       CPPUNIT_ASSERT_EQUAL(system("test -f ./testdir/TestToken"), 0);
+#else
+       CPPUNIT_ASSERT(GetFileAttributes("testdir\\TestToken") != INVALID_FILE_ATTRIBUTES);
+#endif
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection);
+
+void test_a_db_with_a_connection::setUp()
+{
+       test_a_db::setUp();
+       connection = DB::Connection::Create("testdir","TestToken");
+       CPPUNIT_ASSERT(connection != null);
+       CPPUNIT_ASSERT(connection->connect());
+}
+
+void test_a_db_with_a_connection::tearDown()
+{
+       CPPUNIT_ASSERT(connection != null);
+       connection->close();
+       delete connection;
+       test_a_db::tearDown();
+}
+
+void test_a_db_with_a_connection::can_prepare_statements()
+{
+       DB::Statement statement = connection->prepare("PRAGMA database_list;");
+       CPPUNIT_ASSERT(statement.isValid());
+}
+
+void test_a_db_with_a_connection::can_perform_statements()
+{
+       DB::Statement statement = connection->prepare("PRAGMA database_list;");
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+       // only expect a single row in the result, so nextRow should now fail
+       CPPUNIT_ASSERT(!result.nextRow());
+}
+
+void test_a_db_with_a_connection::maintains_correct_refcounts()
+{
+       DB::Statement statement = connection->prepare("PRAGMA database_list;");
+       CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1);
+       {
+               DB::Statement statement1 = statement;
+               DB::Statement statement2 = statement;
+               CPPUNIT_ASSERT_EQUAL(statement.refcount(), 3);
+               CPPUNIT_ASSERT(statement1.isValid());
+               CPPUNIT_ASSERT(statement2.isValid());
+       }
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1);
+
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       // Statement is referenced by the result because it provides the query record cursor state.
+       CPPUNIT_ASSERT_EQUAL(statement.refcount(), 2);
+
+       result = DB::Result();
+       CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1);
+}
+void test_a_db_with_a_connection::can_create_tables()
+{
+       CPPUNIT_ASSERT(!connection->tableExists("object"));
+       DB::Statement cr_object = connection->prepare("create table object (id integer primary key autoincrement);");
+       CPPUNIT_ASSERT(connection->execute(cr_object));
+       CPPUNIT_ASSERT(connection->tableExists("object"));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables);
+
+void test_a_db_with_a_connection_with_tables::setUp()
+{
+       test_a_db_with_a_connection::setUp();
+       can_create_tables();
+
+       // attribute_text
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_text"));
+       DB::Statement cr_attr_text = connection->prepare(
+               "create table attribute_text ("
+               "value text,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_text));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_text"));
+
+       // attribute_integer
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_integer"));
+       DB::Statement cr_attr_integer = connection->prepare(
+               "create table attribute_integer ("
+               "value integer,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_integer));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_integer"));
+
+       // attribute_blob
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_blob"));
+       DB::Statement cr_attr_blob = connection->prepare(
+               "create table attribute_blob ("
+               "value blob,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_blob));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_blob"));
+
+       // attribute_boolean
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_boolean"));
+       DB::Statement cr_attr_boolean = connection->prepare(
+               "create table attribute_boolean ("
+               "value boolean,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_boolean));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_boolean"));
+
+       // attribute_datetime
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_datetime"));
+       DB::Statement cr_attr_datetime = connection->prepare(
+               "create table attribute_datetime ("
+               "value datetime,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_datetime));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_datetime"));
+
+       // attribute_real
+       CPPUNIT_ASSERT(!connection->tableExists("attribute_real"));
+       DB::Statement cr_attr_real = connection->prepare(
+               "create table attribute_real ("
+               "value real,"
+               "type integer,"
+               "object_id integer references object(id) on delete cascade,"
+               "id integer primary key autoincrement)"
+               );
+       CPPUNIT_ASSERT(connection->execute(cr_attr_real));
+       CPPUNIT_ASSERT(connection->tableExists("attribute_real"));
+}
+
+void test_a_db_with_a_connection_with_tables::tearDown()
+{
+       test_a_db_with_a_connection::tearDown();
+}
+
+void test_a_db_with_a_connection_with_tables::can_insert_records()
+{
+       DB::Statement statement = connection->prepare("insert into object default values");
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       statement = connection->prepare(
+                               "insert into attribute_text (value,type,object_id) values ('%s',%d,%lld)",
+                               "testing testing testing",
+                               1234,
+                               object_id);
+       CPPUNIT_ASSERT(connection->execute(statement));
+}
+
+void test_a_db_with_a_connection_with_tables::can_retrieve_records()
+{
+       can_insert_records();
+
+       DB::Statement statement = connection->prepare(
+                               "select value from attribute_text as t where t.type=%d",
+                               1234);
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), std::string("testing testing testing"));
+}
+
+void test_a_db_with_a_connection_with_tables::can_cascade_delete_objects_and_attributes()
+{
+       can_insert_records();
+
+       DB::Statement statement = connection->prepare("select id from object");
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       long long object_id = result.getLongLong(1);
+
+       statement = connection->prepare("delete from object where id=%lld",object_id);
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       statement = connection->prepare("select * from attribute_text where object_id=%lld",object_id);
+       result = connection->perform(statement);
+
+       // Check cascade delete was successful.
+       CPPUNIT_ASSERT(!result.isValid());
+}
+
+
+void test_a_db_with_a_connection_with_tables::can_update_text_attribute()
+{
+       can_insert_records();
+
+       // query all objects
+       DB::Statement statement = connection->prepare("select id from object");
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       long long object_id = result.getLongLong(1); // field indices start at 1
+
+       statement = connection->prepare(
+                               "update attribute_text set value='test test test' where type=%d and object_id=%lld",
+                               1234,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+}
+
+void test_a_db_with_a_connection_with_tables::can_update_text_attribute_bound_value()
+{
+       can_insert_records();
+
+       // query all objects
+       DB::Statement statement = connection->prepare("select id from object");
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       long long object_id = result.getLongLong(1); // field indices start at 1
+
+       statement = connection->prepare(
+                               "update attribute_text set value=? where type=%d and object_id=%lld",
+                               1234,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+
+       std::string msg("testing quote ' and accents é.");
+
+       CPPUNIT_ASSERT(DB::Bindings(statement).bindText(1,msg.c_str(),msg.size(),NULL));
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       statement = connection->prepare(
+                               "select value from attribute_text as t where t.type=%d and t.object_id=%lld",
+                               1234,
+                               object_id);
+       result = connection->perform(statement);
+       CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), msg);
+}
+
+void test_a_db_with_a_connection_with_tables::can_update_integer_attribute_bound_value()
+{
+       // insert new object
+       DB::Statement statement = connection->prepare(
+                               "insert into object default values");
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       // insert integer attribute
+       statement = connection->prepare(
+                               "insert into attribute_integer (value,type,object_id) values (%lld,%d,%lld)",
+                               1111,
+                               1235,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // prepare update integer attribute statement
+       statement = connection->prepare(
+                               "update attribute_integer set value=? where type=%d and object_id=%lld",
+                               1235,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+
+       // bind long long value to the parameter an update the record
+       CPPUNIT_ASSERT(DB::Bindings(statement).bindInt64(1,2222));
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // Retrieve the value from the record
+       DB::Statement retrieveStmt = connection->prepare(
+                               "select value from attribute_integer as t where t.type=%d and t.object_id=%lld",
+                               1235,
+                               object_id);
+       CPPUNIT_ASSERT(retrieveStmt.isValid());
+       DB::Result result = connection->perform(retrieveStmt);
+       CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)2222);
+
+       // verify that binding to a parameter before resetting the statement will fail.
+       DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print);
+       DB::Bindings bindings(statement);
+       CPPUNIT_ASSERT(!bindings.bindInt(1,3333));
+       DB::setLogErrorHandler(eh);
+
+       // reset statement and bind another value to the statement
+       CPPUNIT_ASSERT(bindings.reset());
+       CPPUNIT_ASSERT(bindings.bindInt(1,3333));
+
+       // perform the update statement again with the newly bound value
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // reset the retrieve statement and perform it again to get the latest value of the integer attribute
+       CPPUNIT_ASSERT(retrieveStmt.reset());
+       result = connection->perform(retrieveStmt);
+       CPPUNIT_ASSERT(result.isValid());
+       CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)3333);
+}
+
+void test_a_db_with_a_connection_with_tables::can_update_blob_attribute_bound_value()
+{
+       // insert new object
+       DB::Statement statement = connection->prepare(
+                               "insert into object default values");
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       // insert blob attribute
+       statement = connection->prepare(
+                               "insert into attribute_blob (value,type,object_id) values (X'012345',%d,%lld)",
+                               1236,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // prepare update blob attribute statement
+       statement = connection->prepare(
+                               "update attribute_blob set value=? where type=%d and object_id=%lld",
+                               1236,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+
+       // bind blob (with embedded zero!) to the parameter
+       const char data[] = {10,11,0,12,13,14,15,16};
+       std::string msg(data,sizeof(data));
+       CPPUNIT_ASSERT(DB::Bindings(statement).bindBlob(1,msg.data(),msg.size(),NULL));
+
+       // update the blob value of the attribute
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // retrieve the blob value from the attribute
+       statement = connection->prepare(
+                               "select value from attribute_blob as t where t.type=%d and t.object_id=%lld",
+                               1236,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       // check that the retrieved blob value matches the original data.
+       CPPUNIT_ASSERT_EQUAL(result.getFieldLength(1), sizeof(data));
+       std::string msgstored((const char *)result.getBinary(1),result.getFieldLength(1));
+       CPPUNIT_ASSERT_EQUAL(msg, msgstored);
+}
+
+
+void test_a_db_with_a_connection_with_tables::will_not_insert_non_existing_attribute_on_update()
+{
+       DB::Statement statement;
+       DB::Result result;
+
+       // Insert new object
+       statement = connection->prepare(
+                               "insert into object default values");
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       // Updating an attribute before it is created will succeed, but will not insert an attribute.
+       statement = connection->prepare(
+                               "update attribute_boolean set value=1 where type=%d and object_id=%lld",
+                               1237,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // Retrieve the boolean value from the attribute should fail
+       statement = connection->prepare(
+                               "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld",
+                               1237,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       result = connection->perform(statement);
+       CPPUNIT_ASSERT(!result.isValid());
+}
+
+
+void test_a_db_with_a_connection_with_tables::can_update_boolean_attribute_bound_value()
+{
+       //SQLite doesn't have a boolean data type, use 0 (false) and 1 (true)
+
+       DB::Statement statement;
+       DB::Result result;
+
+       // Insert new object
+       statement = connection->prepare(
+                               "insert into object default values");
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       // insert boolean attribute
+       statement = connection->prepare(
+                               "insert into attribute_boolean (value,type,object_id) values (1,%d,%lld)",
+                               1237,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // prepare update boolean attribute statement
+       statement = connection->prepare(
+                               "update attribute_boolean set value=? where type=%d and object_id=%lld",
+                               1237,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+
+       // Bind 0 (false) to the first parameter
+       CPPUNIT_ASSERT(DB::Bindings(statement).bindInt(1,0));
+
+       // Execute the statement to update the attribute value.
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // Retrieve the boolean value from the attribute
+       statement = connection->prepare(
+                               "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld",
+                               1237,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       // check that the retrieved value matches the original value
+       CPPUNIT_ASSERT_EQUAL(result.getInt(1), 0);
+}
+
+
+void test_a_db_with_a_connection_with_tables::can_update_real_attribute_bound_value()
+{
+       // insert new object
+       DB::Statement statement = connection->prepare(
+                               "insert into object default values");
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+       long long object_id = connection->lastInsertRowId();
+       CPPUNIT_ASSERT(object_id != 0);
+
+       // insert real value
+       statement = connection->prepare(
+                               "insert into attribute_real (value,type,object_id) values(%f,%d,%lld)",
+                               1.238,
+                               1238,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // prepare update real attribute statement
+       statement = connection->prepare(
+                               "update attribute_real set value=? where type=%d and object_id=%lld",
+                               1238,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+
+       // Bind 3333.3333 to the first parameter
+       CPPUNIT_ASSERT(DB::Bindings(statement).bindDouble(1,3333.3333));
+
+       // Execute the statement to update the attribute value
+       CPPUNIT_ASSERT(connection->execute(statement));
+
+       // Retrieve the double value from the attribute
+       statement = connection->prepare(
+                               "select value from attribute_real as t where t.type=%d and t.object_id=%lld",
+                               1238,
+                               object_id);
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       // check that the retrieved value matches the original value.
+       CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001);
+}
+
+void test_a_db_with_a_connection_with_tables::supports_transactions()
+{
+       DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print);
+       CPPUNIT_ASSERT(!connection->rollbackTransaction());
+       DB::setLogErrorHandler(eh);
+
+       CPPUNIT_ASSERT(connection->beginTransactionRW());
+       CPPUNIT_ASSERT(connection->rollbackTransaction());
+
+       eh = DB::setLogErrorHandler(dummy_print);
+       CPPUNIT_ASSERT(!connection->commitTransaction());
+       DB::setLogErrorHandler(eh);
+
+       CPPUNIT_ASSERT(connection->beginTransactionRW());
+       can_update_real_attribute_bound_value();
+       CPPUNIT_ASSERT(connection->commitTransaction());
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables_with_a_second_connection_open);
+
+void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::setUp()
+{
+       test_a_db_with_a_connection_with_tables::setUp();
+       connection2 = DB::Connection::Create("testdir","TestToken");
+       CPPUNIT_ASSERT(connection2 != null);
+       CPPUNIT_ASSERT(connection2->connect());
+       connection2->setBusyTimeout(10);
+}
+
+void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::tearDown()
+{
+       CPPUNIT_ASSERT(connection2 != null);
+       connection2->close();
+       delete connection2;
+       test_a_db_with_a_connection_with_tables::tearDown();
+}
+
+void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::handles_nested_transactions()
+{
+       DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print);
+
+       DB::Connection *connection1 = connection;
+
+       CPPUNIT_ASSERT(connection1->beginTransactionRW());
+
+       CPPUNIT_ASSERT(connection2->beginTransactionRO());
+       CPPUNIT_ASSERT(connection2->rollbackTransaction());
+       CPPUNIT_ASSERT(!connection2->beginTransactionRW());
+
+       CPPUNIT_ASSERT(connection1->commitTransaction());
+
+       DB::setLogErrorHandler(eh);
+}
+
+
+void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::supports_transactions_with_other_connections_open()
+{
+       CPPUNIT_ASSERT(connection2->beginTransactionRO());
+
+       supports_transactions();
+
+       // Retrieve the double value from the attribute
+       DB::Statement statement = connection2->prepare(
+                               "select value from attribute_real as t where t.type=%d and t.object_id=%lld",
+                               1238,
+                               connection->lastInsertRowId());
+       CPPUNIT_ASSERT(statement.isValid());
+       DB::Result result = connection2->perform(statement);
+       CPPUNIT_ASSERT(result.isValid());
+
+       // check that the retrieved value matches the original value.
+       CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001);
+
+       CPPUNIT_ASSERT(connection2->commitTransaction());
+}
diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.h b/SoftHSMv2/src/lib/object_store/test/DBTests.h
new file mode 100644 (file)
index 0000000..422cbce
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBTests.h
+
+ Contains lowest level test cases for the database backend implementation.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBTESTS_H
+#define _SOFTHSM_V2_DBTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "DB.h"
+
+class test_a_db : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(test_a_db);
+       CPPUNIT_TEST(checks_for_empty_connection_parameters);
+       CPPUNIT_TEST(can_be_connected_to_database);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void checks_for_empty_connection_parameters();
+       void can_be_connected_to_database();
+
+       void setUp();
+       void tearDown();
+
+protected:
+       DB::Connection *null;
+
+private:
+};
+
+class test_a_db_with_a_connection : public test_a_db
+{
+       CPPUNIT_TEST_SUITE(test_a_db_with_a_connection);
+       CPPUNIT_TEST(can_prepare_statements);
+       CPPUNIT_TEST(can_perform_statements);
+       CPPUNIT_TEST(maintains_correct_refcounts);
+       CPPUNIT_TEST(can_create_tables);
+       CPPUNIT_TEST_SUITE_END();
+public:
+       void setUp();
+       void tearDown();
+
+       void can_prepare_statements();
+       void can_perform_statements();
+       void maintains_correct_refcounts();
+       void can_create_tables();
+protected:
+       DB::Connection *connection;
+
+private:
+};
+
+class test_a_db_with_a_connection_with_tables : public test_a_db_with_a_connection
+{
+       CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables);
+       CPPUNIT_TEST(can_insert_records);
+       CPPUNIT_TEST(can_retrieve_records);
+       CPPUNIT_TEST(can_cascade_delete_objects_and_attributes);
+       CPPUNIT_TEST(can_update_text_attribute);
+       CPPUNIT_TEST(can_update_text_attribute_bound_value);
+       CPPUNIT_TEST(can_update_integer_attribute_bound_value);
+       CPPUNIT_TEST(can_update_blob_attribute_bound_value);
+       CPPUNIT_TEST(will_not_insert_non_existing_attribute_on_update);
+       CPPUNIT_TEST(can_update_boolean_attribute_bound_value);
+       CPPUNIT_TEST(can_update_real_attribute_bound_value);
+       CPPUNIT_TEST(supports_transactions);
+       CPPUNIT_TEST_SUITE_END();
+public:
+       void setUp();
+       void tearDown();
+
+       void can_insert_records();
+       void can_retrieve_records();
+       void can_cascade_delete_objects_and_attributes();
+       void can_update_text_attribute();
+       void can_update_text_attribute_bound_value();
+       void can_update_integer_attribute_bound_value();
+       void can_update_blob_attribute_bound_value();
+       void will_not_insert_non_existing_attribute_on_update();
+       void can_update_boolean_attribute_bound_value();
+       void can_update_real_attribute_bound_value();
+       void supports_transactions();
+protected:
+
+private:
+};
+
+class test_a_db_with_a_connection_with_tables_with_a_second_connection_open : public test_a_db_with_a_connection_with_tables
+{
+       CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables_with_a_second_connection_open);
+       CPPUNIT_TEST(handles_nested_transactions);
+       CPPUNIT_TEST(supports_transactions_with_other_connections_open);
+       CPPUNIT_TEST_SUITE_END();
+public:
+       void setUp();
+       void tearDown();
+
+       void handles_nested_transactions();
+       void supports_transactions_with_other_connections_open();
+protected:
+       DB::Connection *connection2;
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_DBTESTS_H
diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp
new file mode 100644 (file)
index 0000000..ab0cff1
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBTokenTests.cpp
+
+ Contains test cases to test the database token implementation
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DBTokenTests.h"
+#include "DBToken.h"
+#include "DB.h"
+
+#include <cstdio>
+
+#ifndef HAVE_SQLITE3_H
+#error expected sqlite3 to be available
+#endif
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbtoken);
+
+static int dummy_print(const char *, va_list )
+{
+       return 0;
+}
+
+void test_a_dbtoken::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void test_a_dbtoken::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void test_a_dbtoken::should_be_creatable()
+{
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+
+       ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial);
+
+       CPPUNIT_ASSERT(newToken != NULL);
+
+       CPPUNIT_ASSERT(newToken->isValid());
+
+       delete newToken;
+}
+
+void test_a_dbtoken::should_support_pin_setting_getting()
+{
+       // Create a new token
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+
+       ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial);
+
+       CPPUNIT_ASSERT(newToken != NULL);
+
+       CPPUNIT_ASSERT(newToken->isValid());
+
+       // Check the flags
+       CK_ULONG flags;
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)( CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED));
+
+       // Set the SO PIN
+       ByteString soPIN = "3132333435363738"; // 12345678
+
+       CPPUNIT_ASSERT(newToken->setSOPIN(soPIN));
+
+       // Set the user PIN
+       ByteString userPIN = "31323334"; // 1234
+
+       CPPUNIT_ASSERT(newToken->setUserPIN(userPIN));
+
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       delete newToken;
+
+       // Now reopen the newly created token
+       DBToken reopenedToken("testdir","newToken");
+
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Retrieve the flags, user PIN and so PIN
+       ByteString retrievedSOPIN, retrievedUserPIN;
+
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+}
+
+void test_a_dbtoken::should_allow_object_enumeration()
+{
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+       ByteString soPIN = "31323334"; // 1234
+       ByteString userPIN = "30303030"; // 0000
+       ByteString id[3] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB" };
+
+       {
+               // Instantiate a new token
+               ObjectStoreToken* newToken = new DBToken("testdir", "existingToken", label, serial);
+               CPPUNIT_ASSERT(newToken != NULL);
+               CPPUNIT_ASSERT(newToken->isValid());
+               CPPUNIT_ASSERT(newToken->setSOPIN(soPIN));
+               CPPUNIT_ASSERT(newToken->setUserPIN(userPIN));
+
+               // Test IDs
+               OSAttribute idAtt[3] = { id[0], id[1], id[2] };
+
+               // Create 3 objects on the token
+               OSObject* obj1 = newToken->createObject();
+               CPPUNIT_ASSERT(obj1 != NULL);
+               OSObject* obj2 = newToken->createObject();
+               CPPUNIT_ASSERT(obj2 != NULL);
+               OSObject* obj3 = newToken->createObject();
+               CPPUNIT_ASSERT(obj3 != NULL);
+
+               // Now set the IDs of the 3 objects
+               obj1->startTransaction(OSObject::ReadWrite);
+               CPPUNIT_ASSERT(obj1->setAttribute(CKA_ID, idAtt[0]));
+               obj1->commitTransaction();
+
+               obj2->startTransaction(OSObject::ReadWrite);
+               CPPUNIT_ASSERT(obj2->setAttribute(CKA_ID, idAtt[1]));
+               obj2->commitTransaction();
+
+               obj3->startTransaction(OSObject::ReadWrite);
+               CPPUNIT_ASSERT(obj3->setAttribute(CKA_ID, idAtt[2]));
+               obj3->commitTransaction();
+
+               delete newToken;
+       }
+
+       // Now open the token
+       DBToken existingToken("testdir","existingToken");
+
+       CPPUNIT_ASSERT(existingToken.isValid());
+
+       // Retrieve SO PIN, user PIN, label, serial number and flags
+       ByteString retrievedSOPIN, retrievedUserPIN, retrievedLabel, retrievedSerial;
+       CK_ULONG flags;
+
+       CPPUNIT_ASSERT(existingToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(existingToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(existingToken.getTokenLabel(retrievedLabel));
+       CPPUNIT_ASSERT(existingToken.getTokenSerial(retrievedSerial));
+       CPPUNIT_ASSERT(existingToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT(retrievedLabel == label);
+       CPPUNIT_ASSERT(retrievedSerial == serial);
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       // Check that the token contains 3 objects
+       CPPUNIT_ASSERT_EQUAL(existingToken.getObjects().size(), (size_t)3);
+
+       // Check that all the tokens are presented
+       bool present[3] = { false, false, false };
+       std::set<OSObject*> objects = existingToken.getObjects();
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present[0] = true;
+               }
+               else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1])
+               {
+                       present[1] = true;
+               }
+               else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present[2] = true;
+               }
+       }
+
+       CPPUNIT_ASSERT(present[0]);
+       CPPUNIT_ASSERT(present[1]);
+       CPPUNIT_ASSERT(present[2]);
+}
+
+void test_a_dbtoken::should_fail_to_open_nonexistant_tokens()
+{
+       DBToken doesntExist("testdir","doesntExist");
+
+       CPPUNIT_ASSERT(!doesntExist.isValid());
+}
+
+void test_a_dbtoken::support_create_delete_objects()
+{
+       // Test IDs
+       ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" };
+       OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] };
+       ByteString label = "AABBCCDDEEFF";
+       ByteString serial = "1234567890";
+
+       // Instantiate a new token
+       ObjectStoreToken* testToken = new DBToken("testdir", "testToken", label, serial);
+       CPPUNIT_ASSERT(testToken != NULL);
+       CPPUNIT_ASSERT(testToken->isValid());
+
+       // Open the same token
+       DBToken sameToken("testdir","testToken");
+       CPPUNIT_ASSERT(sameToken.isValid());
+
+       // Create 3 objects on the token
+       OSObject* obj1 = testToken->createObject();
+       CPPUNIT_ASSERT(obj1 != NULL);
+       OSObject* obj2 = testToken->createObject();
+       CPPUNIT_ASSERT(obj2 != NULL);
+       OSObject* obj3 = testToken->createObject();
+       CPPUNIT_ASSERT(obj3 != NULL);
+
+       // Now set the IDs of the 3 objects
+       obj1->setAttribute(CKA_ID, idAtt[0]);
+       obj2->setAttribute(CKA_ID, idAtt[1]);
+       obj3->setAttribute(CKA_ID, idAtt[2]);
+
+       // Check that the token contains 3 objects
+       CPPUNIT_ASSERT_EQUAL(testToken->getObjects().size(), (size_t)3);
+
+       // Check that all three objects are distinct and present
+       std::set<OSObject*> objects = testToken->getObjects();
+       bool present1[3] = { false, false, false };
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present1[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present1[j]);
+       }
+
+       // Now check that the same objects are present in the other instance of the same token
+       std::set<OSObject*> otherObjects = sameToken.getObjects();
+       CPPUNIT_ASSERT_EQUAL(otherObjects.size(), (size_t)3);
+
+       bool present2[3] = { false, false, false };
+
+       for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present2[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present2[j]);
+       }
+
+       // Now delete the second object
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1])
+               {
+                       CPPUNIT_ASSERT(testToken->deleteObject(*i));
+                       break;
+               }
+       }
+
+       // Verify that it was indeed removed
+       CPPUNIT_ASSERT_EQUAL(testToken->getObjects().size(),(size_t)2);
+
+       objects = testToken->getObjects();
+       bool present3[2] = { false, false };
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present3[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present3[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present3[j]);
+       }
+
+       // Now check the other instance
+       CPPUNIT_ASSERT_EQUAL(sameToken.getObjects().size(), (size_t)2);
+
+       otherObjects = sameToken.getObjects();
+       bool present4[2] = { false, false };
+
+       for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present4[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present4[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present4[j]);
+       }
+
+
+       // Release the test token
+       delete testToken;
+}
+
+void test_a_dbtoken::support_clearing_a_token()
+{
+       // Create a new token
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+
+       ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial);
+
+       CPPUNIT_ASSERT(newToken != NULL);
+       CPPUNIT_ASSERT(newToken->isValid());
+
+       // Check the flags
+       CK_ULONG flags;
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED));
+
+       // Set the SO PIN
+       ByteString soPIN = "3132333435363738"; // 12345678
+
+       CPPUNIT_ASSERT(newToken->setSOPIN(soPIN));
+
+       // Set the user PIN
+       ByteString userPIN = "31323334"; // 1234
+
+       CPPUNIT_ASSERT(newToken->setUserPIN(userPIN));
+
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT_EQUAL(flags,  (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       CPPUNIT_ASSERT(newToken->createObject() != NULL);
+
+       delete newToken;
+
+#if 1
+       // Reopen the newly created token and keep a reference around.
+       DBToken referencingToken("testdir", "newToken");
+       CPPUNIT_ASSERT(referencingToken.isValid());
+#endif
+       // Now reopen the newly created token
+       DBToken reopenedToken("testdir","newToken");
+
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Retrieve the flags, user PIN and so PIN
+       ByteString retrievedSOPIN, retrievedUserPIN;
+
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       // Now reset the token
+       CPPUNIT_ASSERT(reopenedToken.resetToken(label));
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(!reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED));
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Now clear the token
+       CPPUNIT_ASSERT(reopenedToken.clearToken());
+       CPPUNIT_ASSERT(!reopenedToken.isValid());
+
+       DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print);
+
+       // Try to open it once more and make sure it has been deleted.
+       DBToken clearedToken("testdir","newToken");
+       CPPUNIT_ASSERT(!clearedToken.isValid());
+
+#if 1
+       // Verify that it is no longer possible to access the database...
+       CPPUNIT_ASSERT(!referencingToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+
+       std::set<OSObject *> objects = referencingToken.getObjects();
+       CPPUNIT_ASSERT_EQUAL(objects.size(), (size_t)0);
+
+       CPPUNIT_ASSERT(!referencingToken.isValid());
+#endif
+
+       DB::setLogErrorHandler(eh);
+}
diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h
new file mode 100644 (file)
index 0000000..de25195
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DBTokenTests.h
+
+ Contains test cases to test the database token implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DBTOKENTESTS_H
+#define _SOFTHSM_V2_DBTOKENTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "DBToken.h"
+
+class test_a_dbtoken : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(test_a_dbtoken);
+       CPPUNIT_TEST(should_be_creatable);
+       CPPUNIT_TEST(should_support_pin_setting_getting);
+       CPPUNIT_TEST(should_allow_object_enumeration);
+       CPPUNIT_TEST(should_fail_to_open_nonexistant_tokens);
+       CPPUNIT_TEST(support_create_delete_objects);
+       CPPUNIT_TEST(support_clearing_a_token);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void should_be_creatable();
+       void should_support_pin_setting_getting();
+       void should_allow_object_enumeration();
+       void should_fail_to_open_nonexistant_tokens();
+       void support_create_delete_objects();
+       void support_clearing_a_token();
+
+protected:
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_DBTOKENTESTS_H
diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp
new file mode 100644 (file)
index 0000000..2b56a5a
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DirectoryTests.cpp
+
+ Contains test cases to test the directory implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "DirectoryTests.h"
+#include "Directory.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DirectoryTests);
+
+void DirectoryTests::setUp()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+       CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir"));
+       CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir2"));
+       CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir3"));
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir/afile"));
+       CPPUNIT_ASSERT(!system("echo someOtherStuff > testdir/anotherFile"));
+       CPPUNIT_ASSERT(!system("echo justStuff > testdir/justaFile"));
+#else
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+       CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir"));
+       CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir2"));
+       CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir3"));
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir\\afile"));
+       CPPUNIT_ASSERT(!system("echo someOtherStuff > testdir\\anotherFile"));
+       CPPUNIT_ASSERT(!system("echo justStuff > testdir\\justaFile"));
+#endif
+}
+
+void DirectoryTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void DirectoryTests::testDirectory()
+{
+#ifndef _WIN32
+       Directory testdir("./testdir");
+#else
+       Directory testdir(".\\testdir");
+#endif
+
+       CPPUNIT_ASSERT(testdir.isValid());
+
+       std::vector<std::string> files = testdir.getFiles();
+       std::vector<std::string> subDirs = testdir.getSubDirs();
+
+       CPPUNIT_ASSERT(files.size() == 3);
+       CPPUNIT_ASSERT(subDirs.size() == 3);
+
+       CPPUNIT_ASSERT(testdir.refresh());
+
+       CPPUNIT_ASSERT(files.size() == 3);
+       CPPUNIT_ASSERT(subDirs.size() == 3);
+
+       bool fileSeen[3] = { false, false, false };
+
+       for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++)
+       {
+               if (!i->compare("afile"))
+               {
+                       fileSeen[0] = true;
+               }
+               else if (!i->compare("anotherFile"))
+               {
+                       fileSeen[1] = true;
+               }
+               else if (!i->compare("justaFile"))
+               {
+                       fileSeen[2] = true;
+               }
+               else
+               {
+                       CPPUNIT_ASSERT(false);
+               }
+       }
+
+       CPPUNIT_ASSERT(fileSeen[0] && fileSeen[1] && fileSeen[2]);
+
+       bool dirSeen[3] = { false, false, false };
+
+       for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++)
+       {
+               if (!i->compare("anotherdir"))
+               {
+                       dirSeen[0] = true;
+               }
+               else if (!i->compare("anotherdir2"))
+               {
+                       dirSeen[1] = true;
+               }
+               else if (!i->compare("anotherdir3"))
+               {
+                       dirSeen[2] = true;
+               }
+               else
+               {
+                       CPPUNIT_ASSERT(false);
+               }
+       }
+
+       CPPUNIT_ASSERT(dirSeen[0] && dirSeen[1] && dirSeen[2]);
+
+       // Create a directory
+       CPPUNIT_ASSERT(testdir.mkdir("newDir"));
+
+       subDirs = testdir.getSubDirs();
+
+       bool dirSeen2[4] = { false, false, false, false };
+
+       for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++)
+       {
+               if (!i->compare("anotherdir"))
+               {
+                       dirSeen2[0] = true;
+               }
+               else if (!i->compare("anotherdir2"))
+               {
+                       dirSeen2[1] = true;
+               }
+               else if (!i->compare("anotherdir3"))
+               {
+                       dirSeen2[2] = true;
+               }
+               else if (!i->compare("newDir"))
+               {
+                       dirSeen2[3] = true;
+               }
+               else
+               {
+                       CPPUNIT_ASSERT(false);
+               }
+       }
+
+       CPPUNIT_ASSERT(dirSeen2[0] && dirSeen2[1] && dirSeen2[2] && dirSeen2[3]);
+
+       // Remove a directory
+       CPPUNIT_ASSERT(testdir.rmdir("anotherdir2", true));
+
+       subDirs = testdir.getSubDirs();
+
+       bool dirSeen3[3] = { false, false, false };
+
+       for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++)
+       {
+               if (!i->compare("anotherdir"))
+               {
+                       dirSeen3[0] = true;
+               }
+               else if (!i->compare("newDir"))
+               {
+                       dirSeen3[1] = true;
+               }
+               else if (!i->compare("anotherdir3"))
+               {
+                       dirSeen3[2] = true;
+               }
+               else
+               {
+                       CPPUNIT_ASSERT(false);
+               }
+       }
+
+       CPPUNIT_ASSERT(dirSeen3[0] && dirSeen3[1] && dirSeen3[2]);
+
+       // Remove a file
+       CPPUNIT_ASSERT(testdir.remove("anotherFile"));
+
+       files = testdir.getFiles();
+
+       bool fileSeen2[2] = { false, false };
+
+       for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++)
+       {
+               if (!i->compare("afile"))
+               {
+                       fileSeen2[0] = true;
+               }
+               else if (!i->compare("justaFile"))
+               {
+                       fileSeen2[1] = true;
+               }
+               else
+               {
+                       CPPUNIT_ASSERT(false);
+               }
+       }
+
+       CPPUNIT_ASSERT(fileSeen2[0] && fileSeen2[1]);
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h
new file mode 100644 (file)
index 0000000..777f1a8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ DirectoryTests.h
+
+ Contains test cases to test the Directory implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DIRECTORYTESTS_H
+#define _SOFTHSM_V2_DIRECTORYTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class DirectoryTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(DirectoryTests);
+       CPPUNIT_TEST(testDirectory);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testDirectory();
+
+       void setUp();
+       void tearDown();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_DIRECTORYTESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.cpp b/SoftHSMv2/src/lib/object_store/test/FileTests.cpp
new file mode 100644 (file)
index 0000000..9ac0979
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ FileTests.cpp
+
+ Contains test cases to test the file implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "FileTests.h"
+#include "File.h"
+#include "Directory.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(FileTests);
+
+// FIXME: all pathnames in this file are *NIX/BSD specific
+
+void FileTests::setUp()
+{
+#ifndef _WIN32
+       int rv = system("rm -rf testdir");
+#else
+       int rv = system("rmdir /s /q testdir 2> nul");
+#endif
+       (void) rv;
+
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void FileTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void FileTests::testExistNotExist()
+{
+       // Test pre-condition
+       CPPUNIT_ASSERT(!exists("nonExistentFile"));
+
+       // Attempt to open a file known not to exist
+#ifndef _WIN32
+       File doesntExist("testdir/nonExistentFile");
+#else
+       File doesntExist("testdir\\nonExistentFile");
+#endif
+
+       CPPUNIT_ASSERT(!doesntExist.isValid());
+
+       // Attempt to open a file known to exist
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir/existingFile"));
+#else
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir\\existingFile"));
+#endif
+       CPPUNIT_ASSERT(exists("existingFile"));
+
+#ifndef _WIN32
+       File exists("testdir/existingFile");
+#else
+       File exists("testdir\\existingFile");
+#endif
+
+       CPPUNIT_ASSERT(exists.isValid());
+}
+
+void FileTests::testCreateNotCreate()
+{
+       // Test pre-condition
+       CPPUNIT_ASSERT(!exists("nonExistentFile"));
+       CPPUNIT_ASSERT(!exists("nonExistentFile2"));
+
+       // Attempt to open a file known not to exist
+#ifndef _WIN32
+       File doesntExist("testdir/nonExistentFile", true, true, false);
+#else
+       File doesntExist("testdir\\nonExistentFile", true, true, false);
+#endif
+
+       CPPUNIT_ASSERT(!doesntExist.isValid());
+       CPPUNIT_ASSERT(!exists("nonExistentFile"));
+
+       // Attempt to open a file known not to exist in create mode
+#ifndef _WIN32
+       File willBeCreated("testdir/nonExistentFile2", true, true, true);
+#else
+       File willBeCreated("testdir\\nonExistentFile2", true, true, true);
+#endif
+
+       CPPUNIT_ASSERT(willBeCreated.isValid());
+       CPPUNIT_ASSERT(exists("nonExistentFile2"));
+}
+
+void FileTests::testLockUnlock()
+{
+       // Create pre-condition
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir/existingFile"));
+#else
+       CPPUNIT_ASSERT(!system("echo someStuff > testdir\\existingFile"));
+#endif
+       CPPUNIT_ASSERT(exists("existingFile"));
+
+#ifndef _WIN32
+       File file1("testdir/existingFile");
+       File file2("testdir/existingFile");
+#else
+       File file1("testdir\\existingFile");
+       File file2("testdir\\existingFile");
+#endif
+
+       CPPUNIT_ASSERT(file1.lock(false));
+       CPPUNIT_ASSERT(!file1.lock(false));
+       CPPUNIT_ASSERT(file2.lock(false));
+       CPPUNIT_ASSERT(file2.unlock());
+       CPPUNIT_ASSERT(file1.unlock());
+       CPPUNIT_ASSERT(file1.lock());
+       CPPUNIT_ASSERT(file2.lock());
+       CPPUNIT_ASSERT(file2.unlock());
+       CPPUNIT_ASSERT(file1.unlock());
+}
+
+void FileTests::testWriteRead()
+{
+       // Generate some test data
+       RNG* rng = CryptoFactory::i()->getRNG();
+
+       ByteString testData1;
+
+       CPPUNIT_ASSERT(rng->generateRandom(testData1, 187));
+
+       // More test data
+       std::string testString = "This is a test of the File class";
+       std::set<CK_MECHANISM_TYPE> testSet;
+       testSet.insert(CKM_RSA_PKCS);
+       testSet.insert(CKM_SHA256_RSA_PKCS);
+
+       // Create a file for writing
+       {
+#ifndef _WIN32
+               File newFile("testdir/newFile", false, true);
+#else
+               File newFile("testdir\\newFile", false, true);
+#endif
+
+               CPPUNIT_ASSERT(newFile.isValid());
+
+               // Write two booleans into the file
+               CPPUNIT_ASSERT(newFile.writeBool(true));
+               CPPUNIT_ASSERT(newFile.writeBool(false));
+
+               // Write an ulong into the file
+               CPPUNIT_ASSERT(newFile.writeULong(0x12345678));
+
+               // Write a ByteString into the file
+               CPPUNIT_ASSERT(newFile.writeByteString(testData1));
+
+               // Write a string into the file
+               CPPUNIT_ASSERT(newFile.writeString(testString));
+
+               // Write a set into the file
+               CPPUNIT_ASSERT(newFile.writeMechanismTypeSet(testSet));
+       }
+
+       CPPUNIT_ASSERT(exists("newFile"));
+
+       // Read the created file back
+       {
+#ifndef _WIN32
+               File newFile("testdir/newFile");
+#else
+               File newFile("testdir\\newFile");
+#endif
+
+               CPPUNIT_ASSERT(newFile.isValid());
+
+               // Read back the two booleans
+               bool b1, b2;
+
+               CPPUNIT_ASSERT(newFile.readBool(b1) && newFile.readBool(b2));
+               CPPUNIT_ASSERT(b1 && !b2);
+
+               // Read back the ulong
+               unsigned long ulongValue;
+
+               CPPUNIT_ASSERT(newFile.readULong(ulongValue));
+               CPPUNIT_ASSERT(ulongValue == 0x12345678);
+
+               // Read back the byte string
+               ByteString bsValue;
+
+               CPPUNIT_ASSERT(newFile.readByteString(bsValue));
+               CPPUNIT_ASSERT(bsValue == testData1);
+
+               // Read back the string value
+               std::string stringVal;
+
+               CPPUNIT_ASSERT(newFile.readString(stringVal));
+               CPPUNIT_ASSERT(!testString.compare(stringVal));
+
+               // Read back the set value
+               std::set<CK_MECHANISM_TYPE> setVal;
+
+               CPPUNIT_ASSERT(newFile.readMechanismTypeSet(setVal));
+               CPPUNIT_ASSERT(setVal == testSet);
+
+               // Check for EOF
+               CPPUNIT_ASSERT(!newFile.readBool(b1));
+               CPPUNIT_ASSERT(newFile.isEOF());
+       }
+}
+
+void FileTests::testSeek()
+{
+       ByteString t1 = "112233445566778899";       // 9 long
+       ByteString t2 = "AABBCCDDEEFFAABBCCDDEEFF"; // 12 long
+
+       {
+               // Create the test file
+#ifndef _WIN32
+               File testFile("testdir/testFile", false, true, true);
+#else
+               File testFile("testdir\\testFile", false, true, true);
+#endif
+
+               CPPUNIT_ASSERT(testFile.isValid());
+
+               // Write the test data to the test file
+               CPPUNIT_ASSERT(testFile.writeByteString(t1) && testFile.writeByteString(t2));
+       }
+
+       // Open the test file for reading
+#ifndef _WIN32
+       File testFile("testdir/testFile");
+#else
+       File testFile("testdir\\testFile");
+#endif
+
+       CPPUNIT_ASSERT(testFile.isValid());
+
+       // First, read back the test data
+       ByteString tr1, tr2;
+
+       CPPUNIT_ASSERT(testFile.readByteString(tr1) && testFile.readByteString(tr2));
+       CPPUNIT_ASSERT(tr1 == t1);
+       CPPUNIT_ASSERT(tr2 == t2);
+
+       // Seek to the length field of the second byte string
+       CPPUNIT_ASSERT(testFile.seek(8+9));
+
+       // Read back the size as an ulong value
+       unsigned long value;
+       unsigned long expectedValue = (unsigned long)0x1122334455667788ULL;
+
+       CPPUNIT_ASSERT(testFile.readULong(value));
+       CPPUNIT_ASSERT(value == 12);
+
+       // Seek to the start of the first byte string's data
+       CPPUNIT_ASSERT(testFile.seek(8));
+
+       // Read back the ulong value stored there
+       CPPUNIT_ASSERT(testFile.readULong(value));
+
+       CPPUNIT_ASSERT(value == expectedValue);
+
+       // Seek to the start of second byte string
+       CPPUNIT_ASSERT(testFile.seek(8+9));
+
+       // Read it
+       ByteString trr2;
+
+       CPPUNIT_ASSERT(testFile.readByteString(trr2));
+       CPPUNIT_ASSERT(trr2 == t2);
+
+       // Rewind the file
+       CPPUNIT_ASSERT(testFile.rewind());
+
+       // Read back both byte strings
+       ByteString trrr1, trrr2;
+
+       CPPUNIT_ASSERT(testFile.readByteString(trrr1) && testFile.readByteString(trrr2));
+       CPPUNIT_ASSERT(trrr1 == t1);
+       CPPUNIT_ASSERT(trrr2 == t2);
+}
+
+bool FileTests::exists(std::string name)
+{
+#ifndef _WIN32
+       Directory dir("./testdir");
+#else
+       Directory dir(".\\testdir");
+#endif
+
+
+       CPPUNIT_ASSERT(dir.isValid());
+
+       std::vector<std::string> files = dir.getFiles();
+
+       for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++)
+       {
+               if (!i->compare(name))
+               {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.h b/SoftHSMv2/src/lib/object_store/test/FileTests.h
new file mode 100644 (file)
index 0000000..0b87f26
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ FileTests.h
+
+ Contains test cases to test the File implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_FILETESTS_H
+#define _SOFTHSM_V2_FILETESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class FileTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(FileTests);
+       CPPUNIT_TEST(testExistNotExist);
+       CPPUNIT_TEST(testCreateNotCreate);
+       CPPUNIT_TEST(testLockUnlock);
+       CPPUNIT_TEST(testWriteRead);
+       CPPUNIT_TEST(testSeek);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testExistNotExist();
+       void testCreateNotCreate();
+       void testLockUnlock();
+       void testWriteRead();
+       void testSeek();
+
+       void setUp();
+       void tearDown();
+
+private:
+       bool exists(std::string path);
+};
+
+#endif // !_SOFTHSM_V2_FILETESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/Makefile.am b/SoftHSMv2/src/lib/object_store/test/Makefile.am
new file mode 100644 (file)
index 0000000..71de7dd
--- /dev/null
@@ -0,0 +1,39 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../.. \
+                               -I$(srcdir)/../../common \
+                               -I$(srcdir)/../../crypto \
+                               -I$(srcdir)/../../data_mgr \
+                               -I$(srcdir)/../../pkcs11 \
+                               -I$(srcdir)/../../session_mgr \
+                               -I$(srcdir)/../../slot_mgr \
+                               @CPPUNIT_CFLAGS@ \
+                               @CRYPTO_INCLUDES@
+
+check_PROGRAMS =               objstoretest
+
+objstoretest_SOURCES =         objstoretest.cpp \
+                               DirectoryTests.cpp \
+                               UUIDTests.cpp \
+                               FileTests.cpp \
+                               ObjectFileTests.cpp \
+                               OSTokenTests.cpp \
+                               ObjectStoreTests.cpp \
+                               SessionObjectTests.cpp \
+                               SessionObjectStoreTests.cpp
+
+if BUILD_OBJECTSTORE_BACKEND_DB
+objstoretest_SOURCES +=                DBTests.cpp \
+                               DBObjectTests.cpp \
+                               DBTokenTests.cpp \
+                               DBObjectStoreTests.cpp
+endif
+
+objstoretest_LDADD =           ../../libsofthsm_convarch.la 
+
+objstoretest_LDFLAGS =                 @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread
+
+TESTS =                        objstoretest
+
+EXTRA_DIST =                   $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp
new file mode 100644 (file)
index 0000000..5afd583
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ OSTokenTests.cpp
+
+ Contains test cases to test the object file implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "OSTokenTests.h"
+#include "OSToken.h"
+#include "ObjectFile.h"
+#include "File.h"
+#include "Directory.h"
+#include "OSAttribute.h"
+#include "OSAttributes.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(OSTokenTests);
+
+// FIXME: all pathnames in this file are *NIX/BSD specific
+
+void OSTokenTests::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void OSTokenTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void OSTokenTests::testNewToken()
+{
+       // Create a new token
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+
+#ifndef _WIN32
+       OSToken* newToken = OSToken::createToken("./testdir", "newToken", label, serial);
+#else
+       OSToken* newToken = OSToken::createToken(".\\testdir", "newToken", label, serial);
+#endif
+
+       CPPUNIT_ASSERT(newToken != NULL);
+
+       // Check the flags
+       CK_ULONG flags;
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED));
+
+       // Set the SO PIN
+       ByteString soPIN = "3132333435363738"; // 12345678
+
+       CPPUNIT_ASSERT(newToken->setSOPIN(soPIN));
+
+       // Set the user PIN
+       ByteString userPIN = "31323334"; // 1234
+
+       CPPUNIT_ASSERT(newToken->setUserPIN(userPIN));
+
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       delete newToken;
+
+       // Now reopen the newly created token
+#ifndef _WIN32
+       OSToken reopenedToken("./testdir/newToken");
+#else
+       OSToken reopenedToken(".\\testdir\\newToken");
+#endif
+
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Retrieve the flags, user PIN and so PIN
+       ByteString retrievedSOPIN, retrievedUserPIN;
+
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+}
+
+void OSTokenTests::testExistingToken()
+{
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+       ByteString soPIN = "31323334"; // 1234
+       ByteString userPIN = "30303030"; // 0000
+       ByteString id1 = "ABCDEF";
+       ByteString id2 = "FEDCBA";
+       ByteString id3 = "AABBCC";
+
+       {
+               // Create the token dir
+#ifndef _WIN32
+               CPPUNIT_ASSERT(!system("mkdir testdir/existingToken"));
+#else
+               CPPUNIT_ASSERT(!system("mkdir testdir\\existingToken"));
+#endif
+
+               // Create the token object
+#ifndef _WIN32
+               ObjectFile tokenObject(NULL, "./testdir/existingToken/token.object", "./testdir/existingToken/token.lock", true);
+#else
+               ObjectFile tokenObject(NULL, ".\\testdir\\existingToken\\token.object", ".\\testdir\\existingToken\\token.lock", true);
+#endif
+
+               OSAttribute labelAtt(label);
+               CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENLABEL, labelAtt));
+               OSAttribute serialAtt(serial);
+               CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENSERIAL, serialAtt));
+               OSAttribute soPINAtt(soPIN);
+               CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_SOPIN, soPINAtt));
+               OSAttribute userPINAtt(userPIN);
+               CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_USERPIN, userPINAtt));
+               CK_ULONG flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED;
+               OSAttribute flagsAtt(flags);
+               CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENFLAGS, flagsAtt));
+
+               // Create 3 objects
+#ifndef _WIN32
+               ObjectFile obj1(NULL, "./testdir/existingToken/1.object", "./testdir/existingToken/1.lock", true);
+               ObjectFile obj2(NULL, "./testdir/existingToken/2.object", "./testdir/existingToken/2.lock", true);
+               ObjectFile obj3(NULL, "./testdir/existingToken/3.object", "./testdir/existingToken/3.lock", true);
+#else
+               ObjectFile obj1(NULL, ".\\testdir\\existingToken\\1.object", ".\\testdir\\existingToken\\1.lock", true);
+               ObjectFile obj2(NULL, ".\\testdir\\existingToken\\2.object", ".\\testdir\\existingToken\\2.lock", true);
+               ObjectFile obj3(NULL, ".\\testdir\\existingToken\\3.object", ".\\testdir\\existingToken\\3.lock", true);
+#endif
+
+               OSAttribute id1Att(id1);
+               OSAttribute id2Att(id2);
+               OSAttribute id3Att(id3);
+
+               CPPUNIT_ASSERT(obj1.setAttribute(CKA_ID, id1));
+               CPPUNIT_ASSERT(obj2.setAttribute(CKA_ID, id2));
+               CPPUNIT_ASSERT(obj3.setAttribute(CKA_ID, id3));
+       }
+
+       // Now open the token
+#ifndef _WIN32
+       OSToken existingToken("./testdir/existingToken");
+#else
+       OSToken existingToken(".\\testdir\\existingToken");
+#endif
+
+
+       CPPUNIT_ASSERT(existingToken.isValid());
+
+       // Retrieve SO PIN, user PIN, label, serial number and flags
+       ByteString retrievedSOPIN, retrievedUserPIN, retrievedLabel, retrievedSerial;
+       CK_ULONG flags;
+
+       CPPUNIT_ASSERT(existingToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(existingToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(existingToken.getTokenLabel(retrievedLabel));
+       CPPUNIT_ASSERT(existingToken.getTokenSerial(retrievedSerial));
+       CPPUNIT_ASSERT(existingToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT(retrievedLabel == label);
+       CPPUNIT_ASSERT(retrievedSerial == serial);
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       // Check that the token contains 3 objects
+       CPPUNIT_ASSERT(existingToken.getObjects().size() == 3);
+
+       // Check that all the tokens are presented
+       bool present[3] = { false, false, false };
+       std::set<OSObject*> objects = existingToken.getObjects();
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id1)
+               {
+                       present[0] = true;
+               }
+               else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id2)
+               {
+                       present[1] = true;
+               }
+               else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id3)
+               {
+                       present[2] = true;
+               }
+       }
+
+       CPPUNIT_ASSERT(present[0] == true);
+       CPPUNIT_ASSERT(present[1] == true);
+       CPPUNIT_ASSERT(present[2] == true);
+}
+
+void OSTokenTests::testNonExistentToken()
+{
+#ifndef _WIN32
+       OSToken doesntExist("./testdir/doesntExist");
+#else
+       OSToken doesntExist(".\\testdir\\doesntExist");
+#endif
+
+       CPPUNIT_ASSERT(!doesntExist.isValid());
+}
+
+void OSTokenTests::testCreateDeleteObjects()
+{
+       // Test IDs
+       ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" };
+       OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] };
+       ByteString label = "AABBCCDDEEFF";
+       ByteString serial = "1234567890";
+
+       // Instantiate a new token
+#ifndef _WIN32
+       OSToken* testToken = OSToken::createToken("./testdir", "testToken", label, serial);
+#else
+       OSToken* testToken = OSToken::createToken(".\\testdir", "testToken", label, serial);
+#endif
+
+       CPPUNIT_ASSERT(testToken != NULL);
+       CPPUNIT_ASSERT(testToken->isValid());
+
+       // Open the same token
+#ifndef _WIN32
+       OSToken sameToken("./testdir/testToken");
+#else
+       OSToken sameToken(".\\testdir\\testToken");
+#endif
+
+       CPPUNIT_ASSERT(sameToken.isValid());
+
+       // Create 3 objects on the token
+       OSObject* obj1 = testToken->createObject();
+       CPPUNIT_ASSERT(obj1 != NULL);
+       OSObject* obj2 = testToken->createObject();
+       CPPUNIT_ASSERT(obj2 != NULL);
+       OSObject* obj3 = testToken->createObject();
+       CPPUNIT_ASSERT(obj3 != NULL);
+
+       // Now set the IDs of the 3 objects
+       obj1->setAttribute(CKA_ID, idAtt[0]);
+       obj2->setAttribute(CKA_ID, idAtt[1]);
+       obj3->setAttribute(CKA_ID, idAtt[2]);
+
+       // Check that the token contains 3 objects
+       CPPUNIT_ASSERT(testToken->getObjects().size() == 3);
+
+       // Check that all three objects are distinct and present
+       std::set<OSObject*> objects = testToken->getObjects();
+       bool present1[3] = { false, false, false };
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present1[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present1[j] == true);
+       }
+
+       // Now check that the same objects are present in the other instance of the same token
+       std::set<OSObject*> otherObjects = sameToken.getObjects();
+       CPPUNIT_ASSERT(otherObjects.size() == 3);
+
+       bool present2[3] = { false, false, false };
+
+       for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present2[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present2[j] == true);
+       }
+
+       // Now delete the second object
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1])
+               {
+                       CPPUNIT_ASSERT(testToken->deleteObject(*i));
+                       break;
+               }
+       }
+
+       // Verify that it was indeed removed
+       CPPUNIT_ASSERT(testToken->getObjects().size() == 2);
+
+       objects = testToken->getObjects();
+       bool present3[2] = { false, false };
+
+       for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present3[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present3[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present3[j] == true);
+       }
+
+       // Now check the other instance
+       CPPUNIT_ASSERT(sameToken.getObjects().size() == 2);
+
+       otherObjects = sameToken.getObjects();
+       bool present4[2] = { false, false };
+
+       for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present4[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present4[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present4[j] == true);
+       }
+
+
+       // Release the test token
+       delete testToken;
+}
+
+void OSTokenTests::testClearToken()
+{
+       // Create a new token
+       ByteString label = "40414243"; // ABCD
+       ByteString serial = "0102030405060708";
+
+#ifndef _WIN32
+       OSToken* newToken = OSToken::createToken("./testdir", "newToken", label, serial);
+#else
+       OSToken* newToken = OSToken::createToken(".\\testdir", "newToken", label, serial);
+#endif
+
+       CPPUNIT_ASSERT(newToken != NULL);
+
+       // Check the flags
+       CK_ULONG flags;
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED));
+
+       // Set the SO PIN
+       ByteString soPIN = "3132333435363738"; // 12345678
+
+       CPPUNIT_ASSERT(newToken->setSOPIN(soPIN));
+
+       // Set the user PIN
+       ByteString userPIN = "31323334"; // 1234
+
+       CPPUNIT_ASSERT(newToken->setUserPIN(userPIN));
+
+       CPPUNIT_ASSERT(newToken->getTokenFlags(flags));
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       delete newToken;
+
+       // Now reopen the newly created token
+#ifndef _WIN32
+       OSToken reopenedToken("./testdir/newToken");
+#else
+       OSToken reopenedToken(".\\testdir\\newToken");
+#endif
+
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Retrieve the flags, user PIN and so PIN
+       ByteString retrievedSOPIN, retrievedUserPIN;
+
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(retrievedUserPIN == userPIN);
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED));
+
+       // Now reset the token
+       CPPUNIT_ASSERT(reopenedToken.resetToken(label));
+       CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN));
+       CPPUNIT_ASSERT(!reopenedToken.getUserPIN(retrievedUserPIN));
+       CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags));
+       CPPUNIT_ASSERT(retrievedSOPIN == soPIN);
+       CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED));
+       CPPUNIT_ASSERT(reopenedToken.isValid());
+
+       // Now clear the token
+       CPPUNIT_ASSERT(reopenedToken.clearToken());
+       CPPUNIT_ASSERT(!reopenedToken.isValid());
+
+       // Try to open it once more
+#ifndef _WIN32
+       OSToken clearedToken("./testdir/newToken");
+#else
+       OSToken clearedToken(".\\testdir\\newToken");
+#endif
+
+       CPPUNIT_ASSERT(!clearedToken.isValid());
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h
new file mode 100644 (file)
index 0000000..1155fcf
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ OSTokenTests.h
+
+ Contains test cases to test the object file implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OSTOKENTESTS_H
+#define _SOFTHSM_V2_OSTOKENTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class OSTokenTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(OSTokenTests);
+       CPPUNIT_TEST(testNewToken);
+       CPPUNIT_TEST(testExistingToken);
+       CPPUNIT_TEST(testNonExistentToken);
+       CPPUNIT_TEST(testCreateDeleteObjects);
+       CPPUNIT_TEST(testClearToken);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testNewToken();
+       void testExistingToken();
+       void testNonExistentToken();
+       void testCreateDeleteObjects();
+       void testClearToken();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_OSTOKENTESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp
new file mode 100644 (file)
index 0000000..9f0f5bd
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectObjectFileTests.cpp
+
+ Contains test cases to test the object file implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "ObjectFileTests.h"
+#include "ObjectFile.h"
+#include "File.h"
+#include "Directory.h"
+#include "OSAttribute.h"
+#include "CryptoFactory.h"
+#include "RNG.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ObjectFileTests);
+
+// FIXME: all pathnames in this file are *NIX/BSD specific
+
+void ObjectFileTests::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void ObjectFileTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void ObjectFileTests::testBoolAttr()
+{
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               bool value2 = false;
+               bool value3 = true;
+               bool value4 = true;
+               bool value5 = false;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).getBooleanValue() == false);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == false);
+
+               bool value6 = true;
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).getBooleanValue() == value6);
+               CPPUNIT_ASSERT(testObject.getBooleanValue(CKA_VERIFY, false) == value6);
+       }
+}
+
+void ObjectFileTests::testULongAttr()
+{
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               unsigned long value1 = 0x12345678;
+               unsigned long value2 = 0x87654321;
+               unsigned long value3 = 0x01010101;
+               unsigned long value4 = 0x10101010;
+               unsigned long value5 = 0xABCDEF;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue() == 0x12345678);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue() == 0x01010101);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue() == 0x10101010);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue() == 0xABCDEF);
+
+               unsigned long value6 = 0x90909090;
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue() == value6);
+               CPPUNIT_ASSERT(testObject.getUnsignedLongValue(CKA_CLASS, 0x0) == value6);
+       }
+}
+
+void ObjectFileTests::testByteStrAttr()
+{
+       ByteString value1 = "010203040506070809";
+       ByteString value2 = "ABABABABABABABABABABABABABABABABAB";
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7";
+       ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD";
+
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+               OSAttribute attr5(value5);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5);
+
+               ByteString value6 = "909090908080808080807070707070FF";
+               OSAttribute attr6(value6);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6);
+       }
+}
+
+void ObjectFileTests::testMechTypeSetAttr()
+{
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               std::set<CK_MECHANISM_TYPE> set;
+               set.insert(CKM_SHA256);
+               set.insert(CKM_SHA512);
+               OSAttribute attr(set);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               std::set<CK_MECHANISM_TYPE> retrieved =
+                               testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue();
+
+               CPPUNIT_ASSERT(retrieved.size() == 2);
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end());
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end());
+               CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end());
+       }
+}
+
+void ObjectFileTests::testAttrMapAttr()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               unsigned long value2 = 0x87654321;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr;
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE, attr3));
+               mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_ALLOWED_MECHANISMS, attr4));
+               OSAttribute attra(mattr);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE));
+
+               std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb =
+                               testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue();
+               CPPUNIT_ASSERT(mattrb.size() == 4);
+               CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(mattrb.find(CKA_VALUE) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(mattrb.find(CKA_ALLOWED_MECHANISMS) != mattrb.end());
+               CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+               CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+       }
+}
+
+void ObjectFileTests::testMixedAttr()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               unsigned long value2 = 0x87654321;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+       }
+}
+
+void ObjectFileTests::testDoubleAttr()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value3a = "466487346943785684957634";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+       std::set<CK_MECHANISM_TYPE> value4a;
+       value4a.insert(CKM_SHA384);
+       value4a.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               unsigned long value2 = 0x87654321;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+               bool value1 = false;
+               unsigned long value2 = 0x76767676;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3a);
+               OSAttribute attr4(value4a);
+
+               // Change the attributes
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+
+               // Check the attributes
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+       }
+
+       // Now re-read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               bool value1 = false;
+               unsigned long value2 = 0x76767676;
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+       }
+}
+
+void ObjectFileTests::testRefresh()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value3a = "466487346943785684957634";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+       std::set<CK_MECHANISM_TYPE> value4a;
+       value4a.insert(CKM_SHA384);
+       value4a.insert(CKM_SHA512);
+
+       // Create the test object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               bool value1 = true;
+               unsigned long value2 = 0x87654321;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3);
+               OSAttribute attr4(value4);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+       }
+
+       // Now read back the object
+       {
+#ifndef _WIN32
+               ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE));
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+               CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+               bool value1 = false;
+               unsigned long value2 = 0x76767676;
+
+               OSAttribute attr1(value1);
+               OSAttribute attr2(value2);
+               OSAttribute attr3(value3a);
+               OSAttribute attr4(value4a);
+
+               // Change the attributes
+               CPPUNIT_ASSERT(testObject.isValid());
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+
+               // Check the attributes
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+               // Open the object a second time
+#ifndef _WIN32
+               ObjectFile testObject2(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+               ObjectFile testObject2(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+               CPPUNIT_ASSERT(testObject2.isValid());
+
+               // Check the attributes on the second instance
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+               // Add an attribute on the second object
+               ByteString id = "0102010201020102010201020102010201020102";
+
+               OSAttribute attr5(id);
+
+               CPPUNIT_ASSERT(testObject2.setAttribute(CKA_ID, attr5));
+
+               // Check the attribute
+               CPPUNIT_ASSERT(testObject2.attributeExists(CKA_ID));
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == id);
+
+               // Now check that the first instance also knows about it
+               CPPUNIT_ASSERT(testObject.isValid());
+               CPPUNIT_ASSERT(testObject.attributeExists(CKA_ID));
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == id);
+
+               // Now change another attribute
+               unsigned long value2a = 0x89898989;
+
+               OSAttribute attr2a(value2a);
+
+               CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a));
+
+               // Check the attribute
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+
+               // Now check that the second instance also knows about the change
+               CPPUNIT_ASSERT(testObject2.isValid());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+               CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       }
+}
+
+void ObjectFileTests::testCorruptFile()
+{
+#ifndef _WIN32
+       FILE* stream = fopen("testdir/test.object", "w");
+#else
+       FILE* stream = fopen("testdir\\test.object", "wb");
+#endif
+       RNG* rng = CryptoFactory::i()->getRNG();
+       ByteString randomData;
+
+       CPPUNIT_ASSERT(stream != NULL);
+       CPPUNIT_ASSERT(rng->generateRandom(randomData, 312));
+       CPPUNIT_ASSERT(fwrite(randomData.const_byte_str(), 1, randomData.size(), stream) == randomData.size());
+       CPPUNIT_ASSERT(!fclose(stream));
+
+#ifndef _WIN32
+       ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+       ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+       CPPUNIT_ASSERT(!testObject.isValid());
+}
+
+void ObjectFileTests::testTransactions()
+{
+       // Create test object instance
+#ifndef _WIN32
+       ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+       ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       std::set<CK_MECHANISM_TYPE> value4;
+       value4.insert(CKM_SHA256);
+       value4.insert(CKM_SHA512);
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+       OSAttribute attr4(value4);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+
+       // Create secondary instance for the same object
+#ifndef _WIN32
+       ObjectFile testObject2(NULL, "testdir/test.object", "testdir/test.lock");
+#else
+       ObjectFile testObject2(NULL, "testdir\\test.object", "testdir\\test.lock");
+#endif
+
+       CPPUNIT_ASSERT(testObject2.isValid());
+
+       // Check that it has the same attributes
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+       // New values
+       bool value1a = false;
+       unsigned long value2a = 0x12345678;
+       ByteString value3a = "ABABABABABABABABABABABABABABAB";
+       std::set<CK_MECHANISM_TYPE> value4a;
+       value4a.insert(CKM_SHA384);
+       value4a.insert(CKM_SHA512);
+
+       OSAttribute attr1a(value1a);
+       OSAttribute attr2a(value2a);
+       OSAttribute attr3a(value3a);
+       OSAttribute attr4a(value4a);
+
+       // Start transaction on object
+       CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite));
+
+       // Change the attributes
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4a));
+
+       // Verify that the attributes were set
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+       // Verify that they are unchanged on the other instance
+       CPPUNIT_ASSERT(testObject2.isValid());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+       // Commit the transaction
+       CPPUNIT_ASSERT(testObject.commitTransaction());
+
+       // Verify that they have now changed on the other instance
+       CPPUNIT_ASSERT(testObject2.isValid());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+       // Start transaction on object
+       CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite));
+
+       // Change the attributes
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4));
+
+       // Verify that the attributes were set
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4);
+
+       // Verify that they are unchanged on the other instance
+       CPPUNIT_ASSERT(testObject2.isValid());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+       // Abort the transaction
+       CPPUNIT_ASSERT(testObject.abortTransaction());
+
+       // Verify that they are unchanged on both instances
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+
+       CPPUNIT_ASSERT(testObject2.isValid());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a);
+       CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a);
+}
+
+void ObjectFileTests::testDestroyObjectFails()
+{
+       // Create test object instance
+#ifndef _WIN32
+       ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true);
+#else
+       ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true);
+#endif
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       OSObject* testIF = (OSObject*) &testObject;
+
+       CPPUNIT_ASSERT(!testIF->destroyObject());
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h
new file mode 100644 (file)
index 0000000..8342a64
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectFileTests.h
+
+ Contains test cases to test the object file implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTFILETESTS_H
+#define _SOFTHSM_V2_OBJECTFILETESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class ObjectFileTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(ObjectFileTests);
+       CPPUNIT_TEST(testBoolAttr);
+       CPPUNIT_TEST(testULongAttr);
+       CPPUNIT_TEST(testByteStrAttr);
+       CPPUNIT_TEST(testMechTypeSetAttr);
+       CPPUNIT_TEST(testAttrMapAttr);
+       CPPUNIT_TEST(testMixedAttr);
+       CPPUNIT_TEST(testDoubleAttr);
+       CPPUNIT_TEST(testRefresh);
+       CPPUNIT_TEST(testCorruptFile);
+       CPPUNIT_TEST(testTransactions);
+       CPPUNIT_TEST(testDestroyObjectFails);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testBoolAttr();
+       void testULongAttr();
+       void testByteStrAttr();
+       void testMechTypeSetAttr();
+       void testAttrMapAttr();
+       void testMixedAttr();
+       void testDoubleAttr();
+       void testRefresh();
+       void testCorruptFile();
+       void testTransactions();
+       void testDestroyObjectFails();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_OBJECTFILETESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp
new file mode 100644 (file)
index 0000000..0cad27b
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectStoreTests.cpp
+
+ Contains test cases to test the object store implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "ObjectStoreTests.h"
+#include "ObjectStore.h"
+#include "File.h"
+#include "Directory.h"
+#include "OSAttribute.h"
+#include "OSAttributes.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStoreTests);
+
+// FIXME: all pathnames in this file are *NIX/BSD specific
+
+void ObjectStoreTests::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void ObjectStoreTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void ObjectStoreTests::testEmptyStore()
+{
+       // Create the store for an empty dir
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 0);
+}
+
+void ObjectStoreTests::testNewTokens()
+{
+       ByteString label1 = "DEADC0FFEE";
+       ByteString label2 = "DEADBEEF";
+
+       {
+               // Create an empty store
+#ifndef _WIN32
+               ObjectStore store("./testdir");
+#else
+               ObjectStore store(".\\testdir");
+#endif
+
+               CPPUNIT_ASSERT(store.getTokenCount() == 0);
+
+               // Create a new token
+               ObjectStoreToken* token1 = store.newToken(label1);
+
+               CPPUNIT_ASSERT(token1 != NULL);
+
+               CPPUNIT_ASSERT(store.getTokenCount() == 1);
+
+               // Create another new token
+               ObjectStoreToken* token2 = store.newToken(label2);
+
+               CPPUNIT_ASSERT(token2 != NULL);
+
+               CPPUNIT_ASSERT(store.getTokenCount() == 2);
+       }
+
+       // Now reopen that same store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 2);
+
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* token1 = store.getToken(0);
+       ObjectStoreToken* token2 = store.getToken(1);
+
+       ByteString retrieveLabel1, retrieveLabel2;
+
+       CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1));
+       CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2));
+
+       CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel2 == label1));
+       CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2));
+
+       ByteString retrieveSerial1, retrieveSerial2;
+
+       CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1));
+       CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2));
+
+       CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2);
+}
+
+void ObjectStoreTests::testExistingTokens()
+{
+       // Create some tokens
+       ByteString label1 = "DEADC0FFEE";
+       ByteString label2 = "DEADBEEF";
+       ByteString serial1 = "0011001100110011";
+       ByteString serial2 = "2233223322332233";
+
+#ifndef _WIN32
+       ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1);
+       ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2);
+#else
+       ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1);
+       ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2);
+#endif
+
+       CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL));
+
+       delete token1;
+       delete token2;
+
+       // Now associate a store with the test directory
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 2);
+
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* retrieveToken1 = store.getToken(0);
+       ObjectStoreToken* retrieveToken2 = store.getToken(1);
+
+       ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2;
+
+       CPPUNIT_ASSERT(retrieveToken1 != NULL);
+       CPPUNIT_ASSERT(retrieveToken2 != NULL);
+
+       CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1));
+       CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2));
+       CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1));
+       CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2));
+
+       CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2));
+       CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2));
+       CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2);
+       CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2));
+       CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2));
+       CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2);
+}
+
+void ObjectStoreTests::testDeleteToken()
+{
+       // Create some tokens
+       ByteString label1 = "DEADC0FFEE";
+       ByteString label2 = "DEADBEEF";
+       ByteString serial1 = "0011001100110011";
+       ByteString serial2 = "2233223322332233";
+
+#ifndef _WIN32
+       ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1);
+       ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2);
+#else
+       ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1);
+       ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2);
+#endif
+
+       CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL));
+
+       delete token1;
+       delete token2;
+
+       // Now associate a store with the test directory
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 2);
+
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* retrieveToken1 = store.getToken(0);
+       ObjectStoreToken* retrieveToken2 = store.getToken(1);
+
+       ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2;
+
+       CPPUNIT_ASSERT(retrieveToken1 != NULL);
+       CPPUNIT_ASSERT(retrieveToken2 != NULL);
+
+       CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1));
+       CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2));
+       CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1));
+       CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2));
+
+       CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2));
+       CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2));
+       CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2);
+       CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2));
+       CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2));
+       CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2);
+
+       // Now, delete token #1
+       CPPUNIT_ASSERT(store.destroyToken(retrieveToken1));
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 1);
+
+       ObjectStoreToken* retrieveToken_ = store.getToken(0);
+
+       ByteString retrieveLabel_,retrieveSerial_;
+
+       CPPUNIT_ASSERT(retrieveToken_->getTokenLabel(retrieveLabel_));
+       CPPUNIT_ASSERT(retrieveToken_->getTokenSerial(retrieveSerial_));
+
+       CPPUNIT_ASSERT(((retrieveLabel_ == label1) && (retrieveSerial_ == serial1)) ||
+                      ((retrieveLabel_ == label2) && (retrieveSerial_ == serial2)));
+
+       // Now add a new token
+       ByteString label3 = "DEADC0FFEEBEEF";
+
+       // Create a new token
+       ObjectStoreToken* tokenNew = store.newToken(label3);
+
+       CPPUNIT_ASSERT(tokenNew != NULL);
+
+       CPPUNIT_ASSERT(store.getTokenCount() == 2);
+
+       // Retrieve both tokens and check that both are present
+       ObjectStoreToken* retrieveToken1_ = store.getToken(0);
+       ObjectStoreToken* retrieveToken2_ = store.getToken(1);
+
+       CPPUNIT_ASSERT(retrieveToken1_ != NULL);
+       CPPUNIT_ASSERT(retrieveToken2_ != NULL);
+
+       CPPUNIT_ASSERT(retrieveToken1_->getTokenLabel(retrieveLabel1));
+       CPPUNIT_ASSERT(retrieveToken2_->getTokenLabel(retrieveLabel2));
+       CPPUNIT_ASSERT(retrieveToken1_->getTokenSerial(retrieveSerial1));
+       CPPUNIT_ASSERT(retrieveToken2_->getTokenSerial(retrieveSerial2));
+
+       CPPUNIT_ASSERT((retrieveLabel1 == label3) || (retrieveLabel2 == label3));
+       CPPUNIT_ASSERT(((retrieveLabel1 == label1) && (retrieveLabel2 != label2)) ||
+                      ((retrieveLabel1 == label2) && (retrieveLabel2 != label1)));
+       CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2);
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h
new file mode 100644 (file)
index 0000000..3f03c5a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ ObjectStoreTests.h
+
+ Contains test cases to test the object store implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTSTORETESTS_H
+#define _SOFTHSM_V2_OBJECTSTORETESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class ObjectStoreTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(ObjectStoreTests);
+       CPPUNIT_TEST(testEmptyStore);
+       CPPUNIT_TEST(testNewTokens);
+       CPPUNIT_TEST(testExistingTokens);
+       CPPUNIT_TEST(testDeleteToken);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testEmptyStore();
+       void testNewTokens();
+       void testExistingTokens();
+       void testDeleteToken();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_OBJECTSTORETESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp
new file mode 100644 (file)
index 0000000..2c41eb0
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SessionObjectStoreTests.cpp
+
+ Contains test cases to test the session object store implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+#include "SessionObjectStoreTests.h"
+#include "SessionObjectStore.h"
+#include "SessionObject.h"
+#include "OSAttribute.h"
+#include "OSAttributes.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SessionObjectStoreTests);
+
+void SessionObjectStoreTests::setUp()
+{
+}
+
+void SessionObjectStoreTests::tearDown()
+{
+}
+
+void SessionObjectStoreTests::testCreateDeleteObjects()
+{
+       // Test IDs
+       ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" };
+       OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] };
+       ByteString label = "AABBCCDDEEFF";
+       ByteString serial = "1234567890";
+
+       // Get access to the session object store
+       SessionObjectStore* testStore = new SessionObjectStore();
+
+       // Create 3 objects in the store
+       SessionObject* obj1 = testStore->createObject(1, 1);
+       CPPUNIT_ASSERT(obj1 != NULL);
+       SessionObject* obj2 = testStore->createObject(1, 1);
+       CPPUNIT_ASSERT(obj2 != NULL);
+       SessionObject* obj3 = testStore->createObject(1, 1);
+       CPPUNIT_ASSERT(obj3 != NULL);
+
+       // Now set the IDs of the 3 objects
+       obj1->setAttribute(CKA_ID, idAtt[0]);
+       obj2->setAttribute(CKA_ID, idAtt[1]);
+       obj3->setAttribute(CKA_ID, idAtt[2]);
+
+       // Check that the store contains 3 objects
+       CPPUNIT_ASSERT(testStore->getObjects().size() == 3);
+
+       // Check that all three objects are distinct and present
+       std::set<SessionObject*> objects = testStore->getObjects();
+       bool present1[3] = { false, false, false };
+
+       for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present1[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present1[j] == true);
+       }
+
+       // Now delete the second object
+       for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1])
+               {
+                       CPPUNIT_ASSERT(testStore->deleteObject(*i));
+                       break;
+               }
+       }
+
+       // Verify that it was indeed removed
+       CPPUNIT_ASSERT(testStore->getObjects().size() == 2);
+
+       objects = testStore->getObjects();
+       bool present3[2] = { false, false };
+
+       for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present3[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present3[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present3[j] == true);
+       }
+
+       delete testStore;
+}
+
+void SessionObjectStoreTests::testMultiSession()
+{
+       // Get access to the store
+       SessionObjectStore* store = new SessionObjectStore();
+
+       // Check that the store is empty
+       CPPUNIT_ASSERT(store->getObjects().size() == 0);
+
+       // Test IDs
+       ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" };
+       OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] };
+
+       // Create 3 objects in the store for three different sessions
+       SessionObject* obj1 = store->createObject(1, 1);
+       CPPUNIT_ASSERT(obj1 != NULL);
+       SessionObject* obj2 = store->createObject(1, 2);
+       CPPUNIT_ASSERT(obj2 != NULL);
+       SessionObject* obj3 = store->createObject(1, 3);
+       CPPUNIT_ASSERT(obj3 != NULL);
+
+       // Now set the IDs of the 3 objects
+       obj1->setAttribute(CKA_ID, idAtt[0]);
+       obj2->setAttribute(CKA_ID, idAtt[1]);
+       obj3->setAttribute(CKA_ID, idAtt[2]);
+
+       // Check that the store contains 3 objects
+       CPPUNIT_ASSERT(store->getObjects().size() == 3);
+
+       // Check that all three objects are distinct and present
+       std::set<SessionObject*> objects = store->getObjects();
+       bool present1[3] = { false, false, false };
+
+       for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               for (int j = 0; j < 3; j++)
+               {
+                       if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j])
+                       {
+                               present1[j] = true;
+                       }
+               }
+       }
+
+       for (int j = 0; j < 3; j++)
+       {
+               CPPUNIT_ASSERT(present1[j] == true);
+       }
+
+       // Now indicate that the second session has been closed
+       store->sessionClosed(2);
+
+       // Verify that it was indeed removed
+       CPPUNIT_ASSERT(store->getObjects().size() == 2);
+
+       objects = store->getObjects();
+       bool present3[2] = { false, false };
+
+       for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++)
+       {
+               ByteString retrievedId;
+
+               CPPUNIT_ASSERT((*i)->isValid());
+               CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID));
+
+               CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute());
+
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0])
+               {
+                       present3[0] = true;
+               }
+               if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2])
+               {
+                       present3[1] = true;
+               }
+       }
+
+       for (int j = 0; j < 2; j++)
+       {
+               CPPUNIT_ASSERT(present3[j] == true);
+       }
+
+       // Create two more objects for session 7
+       SessionObject* obj4 = store->createObject(1, 7);
+       CPPUNIT_ASSERT(obj4 != NULL);
+       SessionObject* obj5 = store->createObject(1, 7);
+       CPPUNIT_ASSERT(obj5 != NULL);
+
+       CPPUNIT_ASSERT(store->getObjects().size() == 4);
+
+       // Close session 1
+       store->sessionClosed(1);
+
+       CPPUNIT_ASSERT(store->getObjects().size() == 3);
+
+       objects = store->getObjects();
+
+       CPPUNIT_ASSERT(objects.find(obj1) == objects.end());
+       CPPUNIT_ASSERT(objects.find(obj2) == objects.end());
+       CPPUNIT_ASSERT(objects.find(obj3) != objects.end());
+       CPPUNIT_ASSERT(objects.find(obj4) != objects.end());
+       CPPUNIT_ASSERT(objects.find(obj5) != objects.end());
+
+       CPPUNIT_ASSERT(!obj1->isValid());
+       CPPUNIT_ASSERT(!obj2->isValid());
+       CPPUNIT_ASSERT(obj3->isValid());
+       CPPUNIT_ASSERT(obj4->isValid());
+       CPPUNIT_ASSERT(obj5->isValid());
+
+       // Close session 7
+       store->sessionClosed(7);
+
+       CPPUNIT_ASSERT(store->getObjects().size() == 1);
+
+       objects = store->getObjects();
+
+       CPPUNIT_ASSERT(objects.find(obj1) == objects.end());
+       CPPUNIT_ASSERT(objects.find(obj2) == objects.end());
+       CPPUNIT_ASSERT(objects.find(obj3) != objects.end());
+       CPPUNIT_ASSERT(objects.find(obj4) == objects.end());
+       CPPUNIT_ASSERT(objects.find(obj5) == objects.end());
+
+       CPPUNIT_ASSERT(!obj1->isValid());
+       CPPUNIT_ASSERT(!obj2->isValid());
+       CPPUNIT_ASSERT(obj3->isValid());
+       CPPUNIT_ASSERT(!obj4->isValid());
+       CPPUNIT_ASSERT(!obj5->isValid());
+
+       delete store;
+}
+
+void SessionObjectStoreTests::testWipeStore()
+{
+       // Get access to the store
+       SessionObjectStore* store = new SessionObjectStore();
+
+       // Check that the store is empty
+       CPPUNIT_ASSERT(store->getObjects().size() == 0);
+
+       // Create 3 objects in the store for three different sessions
+       SessionObject* obj1 = store->createObject(1, 1);
+       CPPUNIT_ASSERT(obj1 != NULL);
+       SessionObject* obj2 = store->createObject(1, 2);
+       CPPUNIT_ASSERT(obj2 != NULL);
+       SessionObject* obj3 = store->createObject(1, 3);
+       CPPUNIT_ASSERT(obj3 != NULL);
+
+       // Wipe the store
+       store->clearStore();
+
+       // Check that the store is empty
+       CPPUNIT_ASSERT(store->getObjects().size() == 0);
+
+       delete store;
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h
new file mode 100644 (file)
index 0000000..374eeaa
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SessionObjectStoreTests.h
+
+ Contains test cases to test the session object store implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H
+#define _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SessionObjectStoreTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(SessionObjectStoreTests);
+       CPPUNIT_TEST(testCreateDeleteObjects);
+       CPPUNIT_TEST(testMultiSession);
+       CPPUNIT_TEST(testWipeStore);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testCreateDeleteObjects();
+       void testMultiSession();
+       void testWipeStore();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp
new file mode 100644 (file)
index 0000000..6183ec6
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SessionObjectTests.cpp
+
+ Contains test cases to test the session object implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "SessionObjectTests.h"
+#include "SessionObject.h"
+#include "File.h"
+#include "Directory.h"
+#include "OSAttribute.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SessionObjectTests);
+
+void SessionObjectTests::setUp()
+{
+}
+
+void SessionObjectTests::tearDown()
+{
+}
+
+void SessionObjectTests::testBoolAttr()
+{
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       bool value2 = false;
+       bool value3 = true;
+       bool value4 = true;
+       bool value5 = false;
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+       OSAttribute attr4(value4);
+       OSAttribute attr5(value5);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).getBooleanValue() == false);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == false);
+
+       bool value6 = true;
+       OSAttribute attr6(value6);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6));
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).getBooleanValue() == value6);
+       CPPUNIT_ASSERT(testObject.getBooleanValue(CKA_VERIFY, false) == value6);
+}
+
+void SessionObjectTests::testULongAttr()
+{
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       unsigned long value1 = 0x12345678;
+       unsigned long value2 = 0x87654321;
+       unsigned long value3 = 0x01010101;
+       unsigned long value4 = 0x10101010;
+       unsigned long value5 = 0xABCDEF;
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+       OSAttribute attr4(value4);
+       OSAttribute attr5(value5);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue() == 0x12345678);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue() == 0x01010101);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue() == 0x10101010);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue() == 0xABCDEF);
+
+       unsigned long value6 = 0x90909090;
+       OSAttribute attr6(value6);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6));
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue() == value6);
+       CPPUNIT_ASSERT(testObject.getUnsignedLongValue(CKA_CLASS, 0x0) == value6);
+}
+
+void SessionObjectTests::testByteStrAttr()
+{
+       ByteString value1 = "010203040506070809";
+       ByteString value2 = "ABABABABABABABABABABABABABABABABAB";
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7";
+       ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD";
+
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+       OSAttribute attr4(value4);
+       OSAttribute attr5(value5);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5);
+
+       ByteString value6 = "909090908080808080807070707070FF";
+       OSAttribute attr6(value6);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6));
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute());
+       CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6);
+}
+
+void SessionObjectTests::testMechTypeSetAttr()
+{
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       std::set<CK_MECHANISM_TYPE> set;
+       set.insert(CKM_SHA256);
+       set.insert(CKM_SHA512);
+
+       OSAttribute attr(set);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr));
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute());
+
+       std::set<CK_MECHANISM_TYPE> retrieved =
+                       testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue();
+
+       CPPUNIT_ASSERT(retrieved.size() == 2);
+       CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end());
+       CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end());
+       CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end());
+}
+
+void SessionObjectTests::testAttrMapAttr()
+{
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr;
+       mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1));
+       mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2));
+       mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE_BITS, attr3));
+       OSAttribute attra(mattr);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_WRAP_TEMPLATE).isAttributeMapAttribute());
+
+       std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb =
+                       testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue();
+       CPPUNIT_ASSERT(mattrb.size() == 3);
+       CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end());
+       CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true);
+       CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end());
+       CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+       CPPUNIT_ASSERT(mattrb.find(CKA_VALUE_BITS) != mattrb.end());
+       CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).isByteStringAttribute());
+       CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).getByteStringValue() == value3);
+
+}
+
+void SessionObjectTests::testMixedAttr()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3);
+}
+
+void SessionObjectTests::testDoubleAttr()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+       ByteString value3a = "466487346943785684957634";
+
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3);
+
+       bool value1a = false;
+       unsigned long value2a = 0x76767676;
+
+       OSAttribute attr1a(value1a);
+       OSAttribute attr2a(value2a);
+       OSAttribute attr3a(value3a);
+
+       // Change the attributes
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a));
+
+       // Check the attributes
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3a);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+}
+
+void SessionObjectTests::testCloseSession()
+{
+       ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328";
+
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       bool value1 = true;
+       unsigned long value2 = 0x87654321;
+
+       OSAttribute attr1(value1);
+       OSAttribute attr2(value2);
+       OSAttribute attr3(value3);
+
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2));
+       CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3));
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS));
+       CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID));
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute());
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute());
+
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321);
+       CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3);
+
+       // Now close the session
+       testObject.removeOnSessionClose(1);
+
+       CPPUNIT_ASSERT(!testObject.isValid());
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_TOKEN));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_PRIME_BITS));
+       CPPUNIT_ASSERT(!testObject.attributeExists(CKA_VALUE_BITS));
+}
+
+void SessionObjectTests::testDestroyObjectFails()
+{
+       // Create test object instance
+       SessionObject testObject(NULL, 1, 1);
+
+       CPPUNIT_ASSERT(testObject.isValid());
+
+       OSObject* testIF = (OSObject*) &testObject;
+
+       CPPUNIT_ASSERT(!testIF->destroyObject());
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h
new file mode 100644 (file)
index 0000000..76fa02e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SessionObjectTests.h
+
+ Contains test cases to test the session object implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONOBJECTTESTS_H
+#define _SOFTHSM_V2_SESSIONOBJECTTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SessionObjectTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(SessionObjectTests);
+       CPPUNIT_TEST(testBoolAttr);
+       CPPUNIT_TEST(testULongAttr);
+       CPPUNIT_TEST(testByteStrAttr);
+       CPPUNIT_TEST(testMechTypeSetAttr);
+       CPPUNIT_TEST(testAttrMapAttr);
+       CPPUNIT_TEST(testMixedAttr);
+       CPPUNIT_TEST(testDoubleAttr);
+       CPPUNIT_TEST(testCloseSession);
+       CPPUNIT_TEST(testDestroyObjectFails);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testBoolAttr();
+       void testULongAttr();
+       void testByteStrAttr();
+       void testMechTypeSetAttr();
+       void testAttrMapAttr();
+       void testMixedAttr();
+       void testDoubleAttr();
+       void testCloseSession();
+       void testDestroyObjectFails();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_SESSIONOBJECTTESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp b/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp
new file mode 100644 (file)
index 0000000..84a49d2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ UUIDTests.cpp
+
+ Contains test cases to test the UUID implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "UUIDTests.h"
+#include "UUID.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(UUIDTests);
+
+void UUIDTests::setUp()
+{
+}
+
+void UUIDTests::tearDown()
+{
+}
+
+void UUIDTests::testUUID()
+{
+       std::string uuid1 = UUID::newUUID();
+       std::string uuid2 = UUID::newUUID();
+       std::string uuid3 = UUID::newUUID();
+
+       CPPUNIT_ASSERT((uuid1.size() == 36) && (uuid2.size() == 36) && (uuid3.size() == 36));
+
+       CPPUNIT_ASSERT(uuid1.compare(uuid2));
+       CPPUNIT_ASSERT(uuid1.compare(uuid3));
+       CPPUNIT_ASSERT(uuid2.compare(uuid3));
+}
+
diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.h b/SoftHSMv2/src/lib/object_store/test/UUIDTests.h
new file mode 100644 (file)
index 0000000..374d509
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ UUIDTests.h
+
+ Contains test cases to test the UUID implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_UUIDTESTS_H
+#define _SOFTHSM_V2_UUIDTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class UUIDTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(UUIDTests);
+       CPPUNIT_TEST(testUUID);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testUUID();
+
+       void setUp();
+       void tearDown();
+
+private:
+};
+
+#endif // !_SOFTHSM_V2_UUIDTESTS_H
+
diff --git a/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp b/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp
new file mode 100644 (file)
index 0000000..7e4b854
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ objstoretest.cpp
+
+ The main test executor for tests on the object store in SoftHSM v2
+ *****************************************************************************/
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/XmlOutputter.h>
+#include <fstream>
+
+#include "config.h"
+#include "MutexFactory.h"
+#include "SecureMemoryRegistry.h"
+
+#if defined(WITH_OPENSSL)
+#include "OSSLCryptoFactory.h"
+#else
+#include "BotanCryptoFactory.h"
+#endif
+
+// Initialise the one-and-only instance
+#ifdef HAVE_CXX11
+
+std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr);
+std::unique_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(nullptr);
+#if defined(WITH_OPENSSL)
+std::unique_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(nullptr);
+#else
+std::unique_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(nullptr);
+#endif
+
+#else
+
+std::auto_ptr<MutexFactory> MutexFactory::instance(NULL);
+std::auto_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(NULL);
+#if defined(WITH_OPENSSL)
+std::auto_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(NULL);
+#else
+std::auto_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(NULL);
+#endif
+
+#endif
+
+int main(int /*argc*/, char** /*argv*/)
+{
+       CppUnit::TestResult controller;
+       CppUnit::TestResultCollector result;
+       CppUnit::TextUi::TestRunner runner;
+       controller.addListener(&result);
+       CppUnit::TestFactoryRegistry &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;
+}
diff --git a/SoftHSMv2/src/lib/pkcs11/cryptoki.h b/SoftHSMv2/src/lib/pkcs11/cryptoki.h
new file mode 100644 (file)
index 0000000..d278b42
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+/*****************************************************************************
+ cryptoki.h
+
+ Set the PKCS#11 macros.
+ *****************************************************************************/
+
+#ifndef _CRYPTOKI_H
+#define _CRYPTOKI_H
+
+#ifdef _WIN32
+#pragma pack(push, cryptoki, 1)
+#endif
+
+// 1. CK_PTR: The indirection string for making a pointer to an
+// object.
+
+#define CK_PTR *
+
+// 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+// an importable Cryptoki library function declaration out of a
+// return type and a function name.
+
+#ifdef _WIN32
+#ifdef CRYPTOKI_EXPORTS
+#define CK_DECLARE_FUNCTION(returnType, name) \
+   returnType __declspec(dllexport) name
+#else
+#define CK_DECLARE_FUNCTION(returnType, name) \
+   returnType __declspec(dllimport) name
+#endif
+#else
+#define CK_DECLARE_FUNCTION(returnType, name) \
+   returnType name
+#endif
+
+// 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+// which makes a Cryptoki API function pointer declaration or
+// function pointer type declaration out of a return type and a
+// function name.
+
+#ifdef _WIN32
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+   returnType __declspec(dllimport) (* name)
+#else
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+   returnType (* name)
+#endif
+
+// 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+// a function pointer type for an application callback out of
+// a return type for the callback and a name for the callback.
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+   returnType (* name)
+
+// 5. NULL_PTR: This macro is the value of a NULL pointer.
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#include "pkcs11.h"
+
+#ifdef _WIN32
+#pragma pack(pop, cryptoki)
+#endif
+
+#endif // !_CRYPTOKI_H
diff --git a/SoftHSMv2/src/lib/pkcs11/pkcs11.h b/SoftHSMv2/src/lib/pkcs11/pkcs11.h
new file mode 100644 (file)
index 0000000..0d78dd7
--- /dev/null
@@ -0,0 +1,265 @@
+/* Copyright (c) OASIS Open 2016. All Rights Reserved./
+ * /Distributed under the terms of the OASIS IPR Policy,
+ * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
+ * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
+ */
+        
+/* Latest version of the specification:
+ * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 5 platform-specific macros must be defined.  These
+ * macros are described below, and typical definitions for them
+ * are also given.  Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 5 macros, the packing convention
+ * for Cryptoki structures should be set.  The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this.  You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object.  It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name.  It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name.  It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV.  It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 5. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h.
+ */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y)      x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points.  That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points.  A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library.  This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+  CK_VERSION    version;  /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKCS11_H_ */
+
diff --git a/SoftHSMv2/src/lib/pkcs11/pkcs11f.h b/SoftHSMv2/src/lib/pkcs11/pkcs11f.h
new file mode 100644 (file)
index 0000000..ed90aff
--- /dev/null
@@ -0,0 +1,939 @@
+/* Copyright (c) OASIS Open 2016. All Rights Reserved./
+ * /Distributed under the terms of the OASIS IPR Policy,
+ * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
+ * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
+ */
+        
+/* Latest version of the specification:
+ * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ */
+
+/* This header file contains pretty much everything about all the
+ * Cryptoki function prototypes.  Because this information is
+ * used for more than just declaring function prototypes, the
+ * order of the functions appearing herein is important, and
+ * should not be altered.
+ */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pInitArgs  /* if this is not NULL_PTR, it gets
+                            * cast to CK_C_INITIALIZE_ARGS_PTR
+                            * and dereferenced
+                            */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_INFO_PTR   pInfo  /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
+                                            * function list
+                                            */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_BBOOL       tokenPresent,  /* only slots with tokens */
+  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
+  CK_ULONG_PTR   pulCount       /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID       slotID,  /* the ID of the slot */
+  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID        slotID,  /* ID of the token's slot */
+  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,          /* ID of token's slot */
+  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
+  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,  /* ID of the token's slot */
+  CK_MECHANISM_TYPE     type,    /* type of mechanism */
+  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID      slotID,    /* ID of the token's slot */
+  CK_UTF8CHAR_PTR pPin,      /* the SO's initial PIN */
+  CK_ULONG        ulPinLen,  /* length in bytes of the PIN */
+  CK_UTF8CHAR_PTR pLabel     /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
+  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
+  CK_ULONG          ulOldLen,  /* length of the old PIN */
+  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
+  CK_ULONG          ulNewLen   /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,        /* the slot's ID */
+  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
+  CK_VOID_PTR           pApplication,  /* passed to callback */
+  CK_NOTIFY             Notify,        /* callback function */
+  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID     slotID  /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE   hSession,  /* the session's handle */
+  CK_SESSION_INFO_PTR pInfo      /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,             /* session's handle */
+  CK_BYTE_PTR       pOperationState,      /* gets state */
+  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR      pOperationState,      /* holds state */
+  CK_ULONG         ulOperationStateLen,  /* holds state length */
+  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
+  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_USER_TYPE      userType,  /* the user type */
+  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
+  CK_ULONG          ulPinLen   /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
+  CK_ULONG          ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
+  CK_ULONG             ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject    /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
+  CK_ULONG_PTR      pulSize    /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
+  CK_ULONG          ulCount     /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE    hSession,          /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
+ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
+ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pData,               /* the plaintext data */
+  CK_ULONG          ulDataLen,           /* bytes of plaintext */
+  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pPart,              /* the plaintext data */
+  CK_ULONG          ulPartLen,          /* plaintext data len */
+  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,                /* session handle */
+  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
+  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
+  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
+  CK_BYTE_PTR       pData,              /* gets plaintext */
+  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
+  CK_ULONG          ulEncryptedPartLen,  /* input length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
+  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pData,        /* data to be digested */
+  CK_ULONG          ulDataLen,    /* bytes of data to digest */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* data to be digested */
+  CK_ULONG          ulPartLen  /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ * signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* the data to sign */
+  CK_ULONG          ulPartLen  /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA).
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pData,          /* signed data */
+  CK_ULONG          ulDataLen,      /* length of signed data */
+  CK_BYTE_PTR       pSignature,     /* signature */
+  CK_ULONG          ulSignatureLen  /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* signed data */
+  CK_ULONG          ulPartLen  /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pSignature,     /* signature to verify */
+  CK_ULONG          ulSignatureLen  /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* signature to verify */
+  CK_ULONG          ulSignatureLen,  /* signature length */
+  CK_BYTE_PTR       pData,           /* gets signed data */
+  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
+  CK_ULONG             ulCount,     /* # of attrs in template */
+  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,                    /* session handle */
+  CK_MECHANISM_PTR     pMechanism,                  /* key-gen mech. */
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template for pub. key */
+  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub. attrs. */
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template for priv. key */
+  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.  attrs. */
+  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub. key handle */
+  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets priv. key handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
+  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
+  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
+  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
+  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
+  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
+  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
+  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
+  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pSeed,     /* the seed material */
+  CK_ULONG          ulSeedLen  /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_BYTE_PTR       RandomData,  /* receives the random data */
+  CK_ULONG          ulRandomLen  /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur.
+ */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FLAGS flags,        /* blocking/nonblocking flag */
+  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
+  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
+);
+#endif
+
diff --git a/SoftHSMv2/src/lib/pkcs11/pkcs11t.h b/SoftHSMv2/src/lib/pkcs11/pkcs11t.h
new file mode 100644 (file)
index 0000000..0cf3acc
--- /dev/null
@@ -0,0 +1,2003 @@
+/* Copyright (c) OASIS Open 2016. All Rights Reserved./
+ * /Distributed under the terms of the OASIS IPR Policy,
+ * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY
+ * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others.
+ */
+        
+/* Latest version of the specification:
+ * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file.
+ */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CRYPTOKI_VERSION_MAJOR          2
+#define CRYPTOKI_VERSION_MINOR          40
+#define CRYPTOKI_VERSION_AMENDMENT      0
+
+#define CK_TRUE         1
+#define CK_FALSE        0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char     CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE           CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE           CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE           CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+typedef long int          CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG          CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION      (~0UL)
+#define CK_EFFECTIVELY_INFINITE         0UL
+
+
+typedef CK_BYTE     CK_PTR   CK_BYTE_PTR;
+typedef CK_CHAR     CK_PTR   CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR   CK_UTF8CHAR_PTR;
+typedef CK_ULONG    CK_PTR   CK_ULONG_PTR;
+typedef void        CK_PTR   CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session
+ * handle or object handle
+ */
+#define CK_INVALID_HANDLE       0UL
+
+
+typedef struct CK_VERSION {
+  CK_BYTE       major;  /* integer portion of version number */
+  CK_BYTE       minor;  /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+  CK_VERSION    cryptokiVersion;     /* Cryptoki interface ver */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_FLAGS      flags;               /* must be zero */
+  CK_UTF8CHAR   libraryDescription[32];  /* blank padded */
+  CK_VERSION    libraryVersion;          /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR    CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application
+ */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER           0UL
+#define CKN_OTP_CHANGED         1UL
+
+typedef CK_ULONG          CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+  CK_UTF8CHAR   slotDescription[64];  /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];   /* blank padded */
+  CK_FLAGS      flags;
+
+  CK_VERSION    hardwareVersion;  /* version of hardware */
+  CK_VERSION    firmwareVersion;  /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag              Mask        Meaning
+ */
+#define CKF_TOKEN_PRESENT     0x00000001UL  /* a token is there */
+#define CKF_REMOVABLE_DEVICE  0x00000002UL  /* removable devices*/
+#define CKF_HW_SLOT           0x00000004UL  /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+  CK_UTF8CHAR   label[32];           /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_UTF8CHAR   model[16];           /* blank padded */
+  CK_CHAR       serialNumber[16];    /* blank padded */
+  CK_FLAGS      flags;               /* see below */
+
+  CK_ULONG      ulMaxSessionCount;     /* max open sessions */
+  CK_ULONG      ulSessionCount;        /* sess. now open */
+  CK_ULONG      ulMaxRwSessionCount;   /* max R/W sessions */
+  CK_ULONG      ulRwSessionCount;      /* R/W sess. now open */
+  CK_ULONG      ulMaxPinLen;           /* in bytes */
+  CK_ULONG      ulMinPinLen;           /* in bytes */
+  CK_ULONG      ulTotalPublicMemory;   /* in bytes */
+  CK_ULONG      ulFreePublicMemory;    /* in bytes */
+  CK_ULONG      ulTotalPrivateMemory;  /* in bytes */
+  CK_ULONG      ulFreePrivateMemory;   /* in bytes */
+  CK_VERSION    hardwareVersion;       /* version of hardware */
+  CK_VERSION    firmwareVersion;       /* version of firmware */
+  CK_CHAR       utcTime[16];           /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ *      Bit Flag                    Mask        Meaning
+ */
+#define CKF_RNG                     0x00000001UL  /* has random # generator */
+#define CKF_WRITE_PROTECTED         0x00000002UL  /* token is write-protected */
+#define CKF_LOGIN_REQUIRED          0x00000004UL  /* user must login */
+#define CKF_USER_PIN_INITIALIZED    0x00000008UL  /* normal user's PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED.  If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state
+ */
+#define CKF_RESTORE_KEY_NOT_NEEDED  0x00000020UL
+
+/* CKF_CLOCK_ON_TOKEN.  If it is set, that means
+ * that the token has some sort of clock.  The time on that
+ * clock is returned in the token info structure
+ */
+#define CKF_CLOCK_ON_TOKEN          0x00000040UL
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH.  If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself
+ */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL
+
+/* CKF_DUAL_CRYPTO_OPERATIONS.  If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign)
+ */
+#define CKF_DUAL_CRYPTO_OPERATIONS  0x00000200UL
+
+/* CKF_TOKEN_INITIALIZED. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized.
+ */
+#define CKF_TOKEN_INITIALIZED       0x00000400UL
+
+/* CKF_SECONDARY_AUTHENTICATION. If it is
+ * true, the token supports secondary authentication for
+ * private key objects.
+ */
+#define CKF_SECONDARY_AUTHENTICATION  0x00000800UL
+
+/* CKF_USER_PIN_COUNT_LOW. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication.
+ */
+#define CKF_USER_PIN_COUNT_LOW       0x00010000UL
+
+/* CKF_USER_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect user PIN will it to become locked.
+ */
+#define CKF_USER_PIN_FINAL_TRY       0x00020000UL
+
+/* CKF_USER_PIN_LOCKED. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible.
+ */
+#define CKF_USER_PIN_LOCKED          0x00040000UL
+
+/* CKF_USER_PIN_TO_BE_CHANGED. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_USER_PIN_TO_BE_CHANGED   0x00080000UL
+
+/* CKF_SO_PIN_COUNT_LOW. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication.
+ */
+#define CKF_SO_PIN_COUNT_LOW         0x00100000UL
+
+/* CKF_SO_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect SO PIN will it to become locked.
+ */
+#define CKF_SO_PIN_FINAL_TRY         0x00200000UL
+
+/* CKF_SO_PIN_LOCKED. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED            0x00400000UL
+
+/* CKF_SO_PIN_TO_BE_CHANGED. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_SO_PIN_TO_BE_CHANGED     0x00800000UL
+
+#define CKF_ERROR_STATE              0x01000000UL
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session
+ */
+typedef CK_ULONG          CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+typedef CK_ULONG          CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO                  0UL
+/* Normal user */
+#define CKU_USER                1UL
+/* Context specific */
+#define CKU_CONTEXT_SPECIFIC    2UL
+
+/* CK_STATE enumerates the session states */
+typedef CK_ULONG          CK_STATE;
+#define CKS_RO_PUBLIC_SESSION   0UL
+#define CKS_RO_USER_FUNCTIONS   1UL
+#define CKS_RW_PUBLIC_SESSION   2UL
+#define CKS_RW_USER_FUNCTIONS   3UL
+#define CKS_RW_SO_FUNCTIONS     4UL
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+  CK_SLOT_ID    slotID;
+  CK_STATE      state;
+  CK_FLAGS      flags;          /* see below */
+  CK_ULONG      ulDeviceError;  /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ *      Bit Flag                Mask        Meaning
+ */
+#define CKF_RW_SESSION          0x00000002UL /* session is r/w */
+#define CKF_SERIAL_SESSION      0x00000004UL /* no parallel    */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object
+ */
+typedef CK_ULONG          CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes.  It is defined
+ * as follows:
+ */
+typedef CK_ULONG          CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+#define CKO_DATA              0x00000000UL
+#define CKO_CERTIFICATE       0x00000001UL
+#define CKO_PUBLIC_KEY        0x00000002UL
+#define CKO_PRIVATE_KEY       0x00000003UL
+#define CKO_SECRET_KEY        0x00000004UL
+#define CKO_HW_FEATURE        0x00000005UL
+#define CKO_DOMAIN_PARAMETERS 0x00000006UL
+#define CKO_MECHANISM         0x00000007UL
+#define CKO_OTP_KEY           0x00000008UL
+
+#define CKO_VENDOR_DEFINED    0x80000000UL
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type
+ * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE.
+ */
+typedef CK_ULONG          CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER  0x00000001UL
+#define CKH_CLOCK              0x00000002UL
+#define CKH_USER_INTERFACE     0x00000003UL
+#define CKH_VENDOR_DEFINED     0x80000000UL
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+typedef CK_ULONG          CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA                 0x00000000UL
+#define CKK_DSA                 0x00000001UL
+#define CKK_DH                  0x00000002UL
+#define CKK_ECDSA               0x00000003UL /* Deprecated */
+#define CKK_EC                  0x00000003UL
+#define CKK_X9_42_DH            0x00000004UL
+#define CKK_KEA                 0x00000005UL
+#define CKK_GENERIC_SECRET      0x00000010UL
+#define CKK_RC2                 0x00000011UL
+#define CKK_RC4                 0x00000012UL
+#define CKK_DES                 0x00000013UL
+#define CKK_DES2                0x00000014UL
+#define CKK_DES3                0x00000015UL
+#define CKK_CAST                0x00000016UL
+#define CKK_CAST3               0x00000017UL
+#define CKK_CAST5               0x00000018UL /* Deprecated */
+#define CKK_CAST128             0x00000018UL
+#define CKK_RC5                 0x00000019UL
+#define CKK_IDEA                0x0000001AUL
+#define CKK_SKIPJACK            0x0000001BUL
+#define CKK_BATON               0x0000001CUL
+#define CKK_JUNIPER             0x0000001DUL
+#define CKK_CDMF                0x0000001EUL
+#define CKK_AES                 0x0000001FUL
+#define CKK_BLOWFISH            0x00000020UL
+#define CKK_TWOFISH             0x00000021UL
+#define CKK_SECURID             0x00000022UL
+#define CKK_HOTP                0x00000023UL
+#define CKK_ACTI                0x00000024UL
+#define CKK_CAMELLIA            0x00000025UL
+#define CKK_ARIA                0x00000026UL
+
+#define CKK_MD5_HMAC            0x00000027UL
+#define CKK_SHA_1_HMAC          0x00000028UL
+#define CKK_RIPEMD128_HMAC      0x00000029UL
+#define CKK_RIPEMD160_HMAC      0x0000002AUL
+#define CKK_SHA256_HMAC         0x0000002BUL
+#define CKK_SHA384_HMAC         0x0000002CUL
+#define CKK_SHA512_HMAC         0x0000002DUL
+#define CKK_SHA224_HMAC         0x0000002EUL
+
+#define CKK_SEED                0x0000002FUL
+#define CKK_GOSTR3410           0x00000030UL
+#define CKK_GOSTR3411           0x00000031UL
+#define CKK_GOST28147           0x00000032UL
+
+
+
+#define CKK_VENDOR_DEFINED      0x80000000UL
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type
+ */
+typedef CK_ULONG          CK_CERTIFICATE_TYPE;
+
+#define CK_CERTIFICATE_CATEGORY_UNSPECIFIED     0UL
+#define CK_CERTIFICATE_CATEGORY_TOKEN_USER      1UL
+#define CK_CERTIFICATE_CATEGORY_AUTHORITY       2UL
+#define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY    3UL
+
+#define CK_SECURITY_DOMAIN_UNSPECIFIED     0UL
+#define CK_SECURITY_DOMAIN_MANUFACTURER    1UL
+#define CK_SECURITY_DOMAIN_OPERATOR        2UL
+#define CK_SECURITY_DOMAIN_THIRD_PARTY     3UL
+
+
+/* The following certificate types are defined: */
+#define CKC_X_509               0x00000000UL
+#define CKC_X_509_ATTR_CERT     0x00000001UL
+#define CKC_WTLS                0x00000002UL
+#define CKC_VENDOR_DEFINED      0x80000000UL
+#define CKC_OPENPGP            (CKC_VENDOR_DEFINED|0x00504750)
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type
+ */
+typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ * consists of an array of values.
+ */
+#define CKF_ARRAY_ATTRIBUTE     0x40000000UL
+
+/* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */
+#define CK_OTP_FORMAT_DECIMAL           0UL
+#define CK_OTP_FORMAT_HEXADECIMAL       1UL
+#define CK_OTP_FORMAT_ALPHANUMERIC      2UL
+#define CK_OTP_FORMAT_BINARY            3UL
+
+/* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT
+ * attributes
+ */
+#define CK_OTP_PARAM_IGNORED            0UL
+#define CK_OTP_PARAM_OPTIONAL           1UL
+#define CK_OTP_PARAM_MANDATORY          2UL
+
+/* The following attribute types are defined: */
+#define CKA_CLASS              0x00000000UL
+#define CKA_TOKEN              0x00000001UL
+#define CKA_PRIVATE            0x00000002UL
+#define CKA_LABEL              0x00000003UL
+#define CKA_APPLICATION        0x00000010UL
+#define CKA_VALUE              0x00000011UL
+#define CKA_OBJECT_ID          0x00000012UL
+#define CKA_CERTIFICATE_TYPE   0x00000080UL
+#define CKA_ISSUER             0x00000081UL
+#define CKA_SERIAL_NUMBER      0x00000082UL
+#define CKA_AC_ISSUER          0x00000083UL
+#define CKA_OWNER              0x00000084UL
+#define CKA_ATTR_TYPES         0x00000085UL
+#define CKA_TRUSTED            0x00000086UL
+#define CKA_CERTIFICATE_CATEGORY        0x00000087UL
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088UL
+#define CKA_URL                         0x00000089UL
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008AUL
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008BUL
+#define CKA_NAME_HASH_ALGORITHM         0x0000008CUL
+#define CKA_CHECK_VALUE                 0x00000090UL
+
+#define CKA_KEY_TYPE           0x00000100UL
+#define CKA_SUBJECT            0x00000101UL
+#define CKA_ID                 0x00000102UL
+#define CKA_SENSITIVE          0x00000103UL
+#define CKA_ENCRYPT            0x00000104UL
+#define CKA_DECRYPT            0x00000105UL
+#define CKA_WRAP               0x00000106UL
+#define CKA_UNWRAP             0x00000107UL
+#define CKA_SIGN               0x00000108UL
+#define CKA_SIGN_RECOVER       0x00000109UL
+#define CKA_VERIFY             0x0000010AUL
+#define CKA_VERIFY_RECOVER     0x0000010BUL
+#define CKA_DERIVE             0x0000010CUL
+#define CKA_START_DATE         0x00000110UL
+#define CKA_END_DATE           0x00000111UL
+#define CKA_MODULUS            0x00000120UL
+#define CKA_MODULUS_BITS       0x00000121UL
+#define CKA_PUBLIC_EXPONENT    0x00000122UL
+#define CKA_PRIVATE_EXPONENT   0x00000123UL
+#define CKA_PRIME_1            0x00000124UL
+#define CKA_PRIME_2            0x00000125UL
+#define CKA_EXPONENT_1         0x00000126UL
+#define CKA_EXPONENT_2         0x00000127UL
+#define CKA_COEFFICIENT        0x00000128UL
+#define CKA_PUBLIC_KEY_INFO    0x00000129UL
+#define CKA_PRIME              0x00000130UL
+#define CKA_SUBPRIME           0x00000131UL
+#define CKA_BASE               0x00000132UL
+
+#define CKA_PRIME_BITS         0x00000133UL
+#define CKA_SUBPRIME_BITS      0x00000134UL
+#define CKA_SUB_PRIME_BITS     CKA_SUBPRIME_BITS
+
+#define CKA_VALUE_BITS         0x00000160UL
+#define CKA_VALUE_LEN          0x00000161UL
+#define CKA_EXTRACTABLE        0x00000162UL
+#define CKA_LOCAL              0x00000163UL
+#define CKA_NEVER_EXTRACTABLE  0x00000164UL
+#define CKA_ALWAYS_SENSITIVE   0x00000165UL
+#define CKA_KEY_GEN_MECHANISM  0x00000166UL
+
+#define CKA_MODIFIABLE         0x00000170UL
+#define CKA_COPYABLE           0x00000171UL
+
+#define CKA_DESTROYABLE        0x00000172UL
+
+#define CKA_ECDSA_PARAMS       0x00000180UL /* Deprecated */
+#define CKA_EC_PARAMS          0x00000180UL
+
+#define CKA_EC_POINT           0x00000181UL
+
+#define CKA_SECONDARY_AUTH     0x00000200UL /* Deprecated */
+#define CKA_AUTH_PIN_FLAGS     0x00000201UL /* Deprecated */
+
+#define CKA_ALWAYS_AUTHENTICATE  0x00000202UL
+
+#define CKA_WRAP_WITH_TRUSTED    0x00000210UL
+#define CKA_WRAP_TEMPLATE        (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
+#define CKA_UNWRAP_TEMPLATE      (CKF_ARRAY_ATTRIBUTE|0x00000212UL)
+#define CKA_DERIVE_TEMPLATE      (CKF_ARRAY_ATTRIBUTE|0x00000213UL)
+
+#define CKA_OTP_FORMAT                0x00000220UL
+#define CKA_OTP_LENGTH                0x00000221UL
+#define CKA_OTP_TIME_INTERVAL         0x00000222UL
+#define CKA_OTP_USER_FRIENDLY_MODE    0x00000223UL
+#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL
+#define CKA_OTP_TIME_REQUIREMENT      0x00000225UL
+#define CKA_OTP_COUNTER_REQUIREMENT   0x00000226UL
+#define CKA_OTP_PIN_REQUIREMENT       0x00000227UL
+#define CKA_OTP_COUNTER               0x0000022EUL
+#define CKA_OTP_TIME                  0x0000022FUL
+#define CKA_OTP_USER_IDENTIFIER       0x0000022AUL
+#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022BUL
+#define CKA_OTP_SERVICE_LOGO          0x0000022CUL
+#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022DUL
+
+#define CKA_GOSTR3410_PARAMS            0x00000250UL
+#define CKA_GOSTR3411_PARAMS            0x00000251UL
+#define CKA_GOST28147_PARAMS            0x00000252UL
+
+#define CKA_HW_FEATURE_TYPE             0x00000300UL
+#define CKA_RESET_ON_INIT               0x00000301UL
+#define CKA_HAS_RESET                   0x00000302UL
+
+#define CKA_PIXEL_X                     0x00000400UL
+#define CKA_PIXEL_Y                     0x00000401UL
+#define CKA_RESOLUTION                  0x00000402UL
+#define CKA_CHAR_ROWS                   0x00000403UL
+#define CKA_CHAR_COLUMNS                0x00000404UL
+#define CKA_COLOR                       0x00000405UL
+#define CKA_BITS_PER_PIXEL              0x00000406UL
+#define CKA_CHAR_SETS                   0x00000480UL
+#define CKA_ENCODING_METHODS            0x00000481UL
+#define CKA_MIME_TYPES                  0x00000482UL
+#define CKA_MECHANISM_TYPE              0x00000500UL
+#define CKA_REQUIRED_CMS_ATTRIBUTES     0x00000501UL
+#define CKA_DEFAULT_CMS_ATTRIBUTES      0x00000502UL
+#define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503UL
+#define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600UL)
+
+#define CKA_VENDOR_DEFINED              0x80000000UL
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute
+ */
+typedef struct CK_ATTRIBUTE {
+  CK_ATTRIBUTE_TYPE type;
+  CK_VOID_PTR       pValue;
+  CK_ULONG          ulValueLen;  /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+  CK_CHAR       year[4];   /* the year ("1900" - "9999") */
+  CK_CHAR       month[2];  /* the month ("01" - "12") */
+  CK_CHAR       day[2];    /* the day   ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type
+ */
+typedef CK_ULONG          CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      0x00000000UL
+#define CKM_RSA_PKCS                   0x00000001UL
+#define CKM_RSA_9796                   0x00000002UL
+#define CKM_RSA_X_509                  0x00000003UL
+
+#define CKM_MD2_RSA_PKCS               0x00000004UL
+#define CKM_MD5_RSA_PKCS               0x00000005UL
+#define CKM_SHA1_RSA_PKCS              0x00000006UL
+
+#define CKM_RIPEMD128_RSA_PKCS         0x00000007UL
+#define CKM_RIPEMD160_RSA_PKCS         0x00000008UL
+#define CKM_RSA_PKCS_OAEP              0x00000009UL
+
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000AUL
+#define CKM_RSA_X9_31                  0x0000000BUL
+#define CKM_SHA1_RSA_X9_31             0x0000000CUL
+#define CKM_RSA_PKCS_PSS               0x0000000DUL
+#define CKM_SHA1_RSA_PKCS_PSS          0x0000000EUL
+
+#define CKM_DSA_KEY_PAIR_GEN           0x00000010UL
+#define CKM_DSA                        0x00000011UL
+#define CKM_DSA_SHA1                   0x00000012UL
+#define CKM_DSA_SHA224                 0x00000013UL
+#define CKM_DSA_SHA256                 0x00000014UL
+#define CKM_DSA_SHA384                 0x00000015UL
+#define CKM_DSA_SHA512                 0x00000016UL
+
+#define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020UL
+#define CKM_DH_PKCS_DERIVE             0x00000021UL
+
+#define CKM_X9_42_DH_KEY_PAIR_GEN      0x00000030UL
+#define CKM_X9_42_DH_DERIVE            0x00000031UL
+#define CKM_X9_42_DH_HYBRID_DERIVE     0x00000032UL
+#define CKM_X9_42_MQV_DERIVE           0x00000033UL
+
+#define CKM_SHA256_RSA_PKCS            0x00000040UL
+#define CKM_SHA384_RSA_PKCS            0x00000041UL
+#define CKM_SHA512_RSA_PKCS            0x00000042UL
+#define CKM_SHA256_RSA_PKCS_PSS        0x00000043UL
+#define CKM_SHA384_RSA_PKCS_PSS        0x00000044UL
+#define CKM_SHA512_RSA_PKCS_PSS        0x00000045UL
+
+#define CKM_SHA224_RSA_PKCS            0x00000046UL
+#define CKM_SHA224_RSA_PKCS_PSS        0x00000047UL
+
+#define CKM_SHA512_224                 0x00000048UL
+#define CKM_SHA512_224_HMAC            0x00000049UL
+#define CKM_SHA512_224_HMAC_GENERAL    0x0000004AUL
+#define CKM_SHA512_224_KEY_DERIVATION  0x0000004BUL
+#define CKM_SHA512_256                 0x0000004CUL
+#define CKM_SHA512_256_HMAC            0x0000004DUL
+#define CKM_SHA512_256_HMAC_GENERAL    0x0000004EUL
+#define CKM_SHA512_256_KEY_DERIVATION  0x0000004FUL
+
+#define CKM_SHA512_T                   0x00000050UL
+#define CKM_SHA512_T_HMAC              0x00000051UL
+#define CKM_SHA512_T_HMAC_GENERAL      0x00000052UL
+#define CKM_SHA512_T_KEY_DERIVATION    0x00000053UL
+
+#define CKM_RC2_KEY_GEN                0x00000100UL
+#define CKM_RC2_ECB                    0x00000101UL
+#define CKM_RC2_CBC                    0x00000102UL
+#define CKM_RC2_MAC                    0x00000103UL
+
+#define CKM_RC2_MAC_GENERAL            0x00000104UL
+#define CKM_RC2_CBC_PAD                0x00000105UL
+
+#define CKM_RC4_KEY_GEN                0x00000110UL
+#define CKM_RC4                        0x00000111UL
+#define CKM_DES_KEY_GEN                0x00000120UL
+#define CKM_DES_ECB                    0x00000121UL
+#define CKM_DES_CBC                    0x00000122UL
+#define CKM_DES_MAC                    0x00000123UL
+
+#define CKM_DES_MAC_GENERAL            0x00000124UL
+#define CKM_DES_CBC_PAD                0x00000125UL
+
+#define CKM_DES2_KEY_GEN               0x00000130UL
+#define CKM_DES3_KEY_GEN               0x00000131UL
+#define CKM_DES3_ECB                   0x00000132UL
+#define CKM_DES3_CBC                   0x00000133UL
+#define CKM_DES3_MAC                   0x00000134UL
+
+#define CKM_DES3_MAC_GENERAL           0x00000135UL
+#define CKM_DES3_CBC_PAD               0x00000136UL
+#define CKM_DES3_CMAC_GENERAL          0x00000137UL
+#define CKM_DES3_CMAC                  0x00000138UL
+#define CKM_CDMF_KEY_GEN               0x00000140UL
+#define CKM_CDMF_ECB                   0x00000141UL
+#define CKM_CDMF_CBC                   0x00000142UL
+#define CKM_CDMF_MAC                   0x00000143UL
+#define CKM_CDMF_MAC_GENERAL           0x00000144UL
+#define CKM_CDMF_CBC_PAD               0x00000145UL
+
+#define CKM_DES_OFB64                  0x00000150UL
+#define CKM_DES_OFB8                   0x00000151UL
+#define CKM_DES_CFB64                  0x00000152UL
+#define CKM_DES_CFB8                   0x00000153UL
+
+#define CKM_MD2                        0x00000200UL
+
+#define CKM_MD2_HMAC                   0x00000201UL
+#define CKM_MD2_HMAC_GENERAL           0x00000202UL
+
+#define CKM_MD5                        0x00000210UL
+
+#define CKM_MD5_HMAC                   0x00000211UL
+#define CKM_MD5_HMAC_GENERAL           0x00000212UL
+
+#define CKM_SHA_1                      0x00000220UL
+
+#define CKM_SHA_1_HMAC                 0x00000221UL
+#define CKM_SHA_1_HMAC_GENERAL         0x00000222UL
+
+#define CKM_RIPEMD128                  0x00000230UL
+#define CKM_RIPEMD128_HMAC             0x00000231UL
+#define CKM_RIPEMD128_HMAC_GENERAL     0x00000232UL
+#define CKM_RIPEMD160                  0x00000240UL
+#define CKM_RIPEMD160_HMAC             0x00000241UL
+#define CKM_RIPEMD160_HMAC_GENERAL     0x00000242UL
+
+#define CKM_SHA256                     0x00000250UL
+#define CKM_SHA256_HMAC                0x00000251UL
+#define CKM_SHA256_HMAC_GENERAL        0x00000252UL
+#define CKM_SHA224                     0x00000255UL
+#define CKM_SHA224_HMAC                0x00000256UL
+#define CKM_SHA224_HMAC_GENERAL        0x00000257UL
+#define CKM_SHA384                     0x00000260UL
+#define CKM_SHA384_HMAC                0x00000261UL
+#define CKM_SHA384_HMAC_GENERAL        0x00000262UL
+#define CKM_SHA512                     0x00000270UL
+#define CKM_SHA512_HMAC                0x00000271UL
+#define CKM_SHA512_HMAC_GENERAL        0x00000272UL
+#define CKM_SECURID_KEY_GEN            0x00000280UL
+#define CKM_SECURID                    0x00000282UL
+#define CKM_HOTP_KEY_GEN               0x00000290UL
+#define CKM_HOTP                       0x00000291UL
+#define CKM_ACTI                       0x000002A0UL
+#define CKM_ACTI_KEY_GEN               0x000002A1UL
+
+#define CKM_CAST_KEY_GEN               0x00000300UL
+#define CKM_CAST_ECB                   0x00000301UL
+#define CKM_CAST_CBC                   0x00000302UL
+#define CKM_CAST_MAC                   0x00000303UL
+#define CKM_CAST_MAC_GENERAL           0x00000304UL
+#define CKM_CAST_CBC_PAD               0x00000305UL
+#define CKM_CAST3_KEY_GEN              0x00000310UL
+#define CKM_CAST3_ECB                  0x00000311UL
+#define CKM_CAST3_CBC                  0x00000312UL
+#define CKM_CAST3_MAC                  0x00000313UL
+#define CKM_CAST3_MAC_GENERAL          0x00000314UL
+#define CKM_CAST3_CBC_PAD              0x00000315UL
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST5_KEY_GEN              0x00000320UL
+#define CKM_CAST128_KEY_GEN            0x00000320UL
+#define CKM_CAST5_ECB                  0x00000321UL
+#define CKM_CAST128_ECB                0x00000321UL
+#define CKM_CAST5_CBC                  0x00000322UL /* Deprecated */
+#define CKM_CAST128_CBC                0x00000322UL
+#define CKM_CAST5_MAC                  0x00000323UL /* Deprecated */
+#define CKM_CAST128_MAC                0x00000323UL
+#define CKM_CAST5_MAC_GENERAL          0x00000324UL /* Deprecated */
+#define CKM_CAST128_MAC_GENERAL        0x00000324UL
+#define CKM_CAST5_CBC_PAD              0x00000325UL /* Deprecated */
+#define CKM_CAST128_CBC_PAD            0x00000325UL
+#define CKM_RC5_KEY_GEN                0x00000330UL
+#define CKM_RC5_ECB                    0x00000331UL
+#define CKM_RC5_CBC                    0x00000332UL
+#define CKM_RC5_MAC                    0x00000333UL
+#define CKM_RC5_MAC_GENERAL            0x00000334UL
+#define CKM_RC5_CBC_PAD                0x00000335UL
+#define CKM_IDEA_KEY_GEN               0x00000340UL
+#define CKM_IDEA_ECB                   0x00000341UL
+#define CKM_IDEA_CBC                   0x00000342UL
+#define CKM_IDEA_MAC                   0x00000343UL
+#define CKM_IDEA_MAC_GENERAL           0x00000344UL
+#define CKM_IDEA_CBC_PAD               0x00000345UL
+#define CKM_GENERIC_SECRET_KEY_GEN     0x00000350UL
+#define CKM_CONCATENATE_BASE_AND_KEY   0x00000360UL
+#define CKM_CONCATENATE_BASE_AND_DATA  0x00000362UL
+#define CKM_CONCATENATE_DATA_AND_BASE  0x00000363UL
+#define CKM_XOR_BASE_AND_DATA          0x00000364UL
+#define CKM_EXTRACT_KEY_FROM_KEY       0x00000365UL
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    0x00000370UL
+#define CKM_SSL3_MASTER_KEY_DERIVE     0x00000371UL
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    0x00000372UL
+
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  0x00000373UL
+#define CKM_TLS_PRE_MASTER_KEY_GEN     0x00000374UL
+#define CKM_TLS_MASTER_KEY_DERIVE      0x00000375UL
+#define CKM_TLS_KEY_AND_MAC_DERIVE     0x00000376UL
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   0x00000377UL
+
+#define CKM_TLS_PRF                    0x00000378UL
+
+#define CKM_SSL3_MD5_MAC               0x00000380UL
+#define CKM_SSL3_SHA1_MAC              0x00000381UL
+#define CKM_MD5_KEY_DERIVATION         0x00000390UL
+#define CKM_MD2_KEY_DERIVATION         0x00000391UL
+#define CKM_SHA1_KEY_DERIVATION        0x00000392UL
+
+#define CKM_SHA256_KEY_DERIVATION      0x00000393UL
+#define CKM_SHA384_KEY_DERIVATION      0x00000394UL
+#define CKM_SHA512_KEY_DERIVATION      0x00000395UL
+#define CKM_SHA224_KEY_DERIVATION      0x00000396UL
+
+#define CKM_PBE_MD2_DES_CBC            0x000003A0UL
+#define CKM_PBE_MD5_DES_CBC            0x000003A1UL
+#define CKM_PBE_MD5_CAST_CBC           0x000003A2UL
+#define CKM_PBE_MD5_CAST3_CBC          0x000003A3UL
+#define CKM_PBE_MD5_CAST5_CBC          0x000003A4UL /* Deprecated */
+#define CKM_PBE_MD5_CAST128_CBC        0x000003A4UL
+#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5UL /* Deprecated */
+#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5UL
+#define CKM_PBE_SHA1_RC4_128           0x000003A6UL
+#define CKM_PBE_SHA1_RC4_40            0x000003A7UL
+#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8UL
+#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9UL
+#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AAUL
+#define CKM_PBE_SHA1_RC2_40_CBC        0x000003ABUL
+
+#define CKM_PKCS5_PBKD2                0x000003B0UL
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0UL
+
+#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0UL
+#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1UL
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2UL
+#define CKM_WTLS_PRF                        0x000003D3UL
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4UL
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5UL
+
+#define CKM_TLS10_MAC_SERVER                0x000003D6UL
+#define CKM_TLS10_MAC_CLIENT                0x000003D7UL
+#define CKM_TLS12_MAC                       0x000003D8UL
+#define CKM_TLS12_KDF                       0x000003D9UL
+#define CKM_TLS12_MASTER_KEY_DERIVE         0x000003E0UL
+#define CKM_TLS12_KEY_AND_MAC_DERIVE        0x000003E1UL
+#define CKM_TLS12_MASTER_KEY_DERIVE_DH      0x000003E2UL
+#define CKM_TLS12_KEY_SAFE_DERIVE           0x000003E3UL
+#define CKM_TLS_MAC                         0x000003E4UL
+#define CKM_TLS_KDF                         0x000003E5UL
+
+#define CKM_KEY_WRAP_LYNKS             0x00000400UL
+#define CKM_KEY_WRAP_SET_OAEP          0x00000401UL
+
+#define CKM_CMS_SIG                    0x00000500UL
+#define CKM_KIP_DERIVE                 0x00000510UL
+#define CKM_KIP_WRAP                   0x00000511UL
+#define CKM_KIP_MAC                    0x00000512UL
+
+#define CKM_CAMELLIA_KEY_GEN           0x00000550UL
+#define CKM_CAMELLIA_ECB               0x00000551UL
+#define CKM_CAMELLIA_CBC               0x00000552UL
+#define CKM_CAMELLIA_MAC               0x00000553UL
+#define CKM_CAMELLIA_MAC_GENERAL       0x00000554UL
+#define CKM_CAMELLIA_CBC_PAD           0x00000555UL
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA  0x00000556UL
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA  0x00000557UL
+#define CKM_CAMELLIA_CTR               0x00000558UL
+
+#define CKM_ARIA_KEY_GEN               0x00000560UL
+#define CKM_ARIA_ECB                   0x00000561UL
+#define CKM_ARIA_CBC                   0x00000562UL
+#define CKM_ARIA_MAC                   0x00000563UL
+#define CKM_ARIA_MAC_GENERAL           0x00000564UL
+#define CKM_ARIA_CBC_PAD               0x00000565UL
+#define CKM_ARIA_ECB_ENCRYPT_DATA      0x00000566UL
+#define CKM_ARIA_CBC_ENCRYPT_DATA      0x00000567UL
+
+#define CKM_SEED_KEY_GEN               0x00000650UL
+#define CKM_SEED_ECB                   0x00000651UL
+#define CKM_SEED_CBC                   0x00000652UL
+#define CKM_SEED_MAC                   0x00000653UL
+#define CKM_SEED_MAC_GENERAL           0x00000654UL
+#define CKM_SEED_CBC_PAD               0x00000655UL
+#define CKM_SEED_ECB_ENCRYPT_DATA      0x00000656UL
+#define CKM_SEED_CBC_ENCRYPT_DATA      0x00000657UL
+
+#define CKM_SKIPJACK_KEY_GEN           0x00001000UL
+#define CKM_SKIPJACK_ECB64             0x00001001UL
+#define CKM_SKIPJACK_CBC64             0x00001002UL
+#define CKM_SKIPJACK_OFB64             0x00001003UL
+#define CKM_SKIPJACK_CFB64             0x00001004UL
+#define CKM_SKIPJACK_CFB32             0x00001005UL
+#define CKM_SKIPJACK_CFB16             0x00001006UL
+#define CKM_SKIPJACK_CFB8              0x00001007UL
+#define CKM_SKIPJACK_WRAP              0x00001008UL
+#define CKM_SKIPJACK_PRIVATE_WRAP      0x00001009UL
+#define CKM_SKIPJACK_RELAYX            0x0000100aUL
+#define CKM_KEA_KEY_PAIR_GEN           0x00001010UL
+#define CKM_KEA_KEY_DERIVE             0x00001011UL
+#define CKM_KEA_DERIVE                 0x00001012UL
+#define CKM_FORTEZZA_TIMESTAMP         0x00001020UL
+#define CKM_BATON_KEY_GEN              0x00001030UL
+#define CKM_BATON_ECB128               0x00001031UL
+#define CKM_BATON_ECB96                0x00001032UL
+#define CKM_BATON_CBC128               0x00001033UL
+#define CKM_BATON_COUNTER              0x00001034UL
+#define CKM_BATON_SHUFFLE              0x00001035UL
+#define CKM_BATON_WRAP                 0x00001036UL
+
+#define CKM_ECDSA_KEY_PAIR_GEN         0x00001040UL /* Deprecated */
+#define CKM_EC_KEY_PAIR_GEN            0x00001040UL
+
+#define CKM_ECDSA                      0x00001041UL
+#define CKM_ECDSA_SHA1                 0x00001042UL
+#define CKM_ECDSA_SHA224               0x00001043UL
+#define CKM_ECDSA_SHA256               0x00001044UL
+#define CKM_ECDSA_SHA384               0x00001045UL
+#define CKM_ECDSA_SHA512               0x00001046UL
+
+#define CKM_ECDH1_DERIVE               0x00001050UL
+#define CKM_ECDH1_COFACTOR_DERIVE      0x00001051UL
+#define CKM_ECMQV_DERIVE               0x00001052UL
+
+#define CKM_ECDH_AES_KEY_WRAP          0x00001053UL
+#define CKM_RSA_AES_KEY_WRAP           0x00001054UL
+
+#define CKM_JUNIPER_KEY_GEN            0x00001060UL
+#define CKM_JUNIPER_ECB128             0x00001061UL
+#define CKM_JUNIPER_CBC128             0x00001062UL
+#define CKM_JUNIPER_COUNTER            0x00001063UL
+#define CKM_JUNIPER_SHUFFLE            0x00001064UL
+#define CKM_JUNIPER_WRAP               0x00001065UL
+#define CKM_FASTHASH                   0x00001070UL
+
+#define CKM_AES_KEY_GEN                0x00001080UL
+#define CKM_AES_ECB                    0x00001081UL
+#define CKM_AES_CBC                    0x00001082UL
+#define CKM_AES_MAC                    0x00001083UL
+#define CKM_AES_MAC_GENERAL            0x00001084UL
+#define CKM_AES_CBC_PAD                0x00001085UL
+#define CKM_AES_CTR                    0x00001086UL
+#define CKM_AES_GCM                    0x00001087UL
+#define CKM_AES_CCM                    0x00001088UL
+#define CKM_AES_CTS                    0x00001089UL
+#define CKM_AES_CMAC                   0x0000108AUL
+#define CKM_AES_CMAC_GENERAL           0x0000108BUL
+
+#define CKM_AES_XCBC_MAC               0x0000108CUL
+#define CKM_AES_XCBC_MAC_96            0x0000108DUL
+#define CKM_AES_GMAC                   0x0000108EUL
+
+#define CKM_BLOWFISH_KEY_GEN           0x00001090UL
+#define CKM_BLOWFISH_CBC               0x00001091UL
+#define CKM_TWOFISH_KEY_GEN            0x00001092UL
+#define CKM_TWOFISH_CBC                0x00001093UL
+#define CKM_BLOWFISH_CBC_PAD           0x00001094UL
+#define CKM_TWOFISH_CBC_PAD            0x00001095UL
+
+#define CKM_DES_ECB_ENCRYPT_DATA       0x00001100UL
+#define CKM_DES_CBC_ENCRYPT_DATA       0x00001101UL
+#define CKM_DES3_ECB_ENCRYPT_DATA      0x00001102UL
+#define CKM_DES3_CBC_ENCRYPT_DATA      0x00001103UL
+#define CKM_AES_ECB_ENCRYPT_DATA       0x00001104UL
+#define CKM_AES_CBC_ENCRYPT_DATA       0x00001105UL
+
+#define CKM_GOSTR3410_KEY_PAIR_GEN     0x00001200UL
+#define CKM_GOSTR3410                  0x00001201UL
+#define CKM_GOSTR3410_WITH_GOSTR3411   0x00001202UL
+#define CKM_GOSTR3410_KEY_WRAP         0x00001203UL
+#define CKM_GOSTR3410_DERIVE           0x00001204UL
+#define CKM_GOSTR3411                  0x00001210UL
+#define CKM_GOSTR3411_HMAC             0x00001211UL
+#define CKM_GOST28147_KEY_GEN          0x00001220UL
+#define CKM_GOST28147_ECB              0x00001221UL
+#define CKM_GOST28147                  0x00001222UL
+#define CKM_GOST28147_MAC              0x00001223UL
+#define CKM_GOST28147_KEY_WRAP         0x00001224UL
+
+#define CKM_DSA_PARAMETER_GEN          0x00002000UL
+#define CKM_DH_PKCS_PARAMETER_GEN      0x00002001UL
+#define CKM_X9_42_DH_PARAMETER_GEN     0x00002002UL
+#define CKM_DSA_PROBABLISTIC_PARAMETER_GEN    0x00002003UL
+#define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN    0x00002004UL
+
+#define CKM_AES_OFB                    0x00002104UL
+#define CKM_AES_CFB64                  0x00002105UL
+#define CKM_AES_CFB8                   0x00002106UL
+#define CKM_AES_CFB128                 0x00002107UL
+
+#define CKM_AES_CFB1                   0x00002108UL
+#define CKM_AES_KEY_WRAP               0x00002109UL     /* WAS: 0x00001090 */
+#define CKM_AES_KEY_WRAP_PAD           0x0000210AUL     /* WAS: 0x00001091 */
+
+#define CKM_RSA_PKCS_TPM_1_1           0x00004001UL
+#define CKM_RSA_PKCS_OAEP_TPM_1_1      0x00004002UL
+
+#define CKM_VENDOR_DEFINED             0x80000000UL
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM {
+  CK_MECHANISM_TYPE mechanism;
+  CK_VOID_PTR       pParameter;
+  CK_ULONG          ulParameterLen;  /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM_INFO {
+    CK_ULONG    ulMinKeySize;
+    CK_ULONG    ulMaxKeySize;
+    CK_FLAGS    flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ *      Bit Flag               Mask          Meaning */
+#define CKF_HW                 0x00000001UL  /* performed by HW */
+
+/* Specify whether or not a mechanism can be used for a particular task */
+#define CKF_ENCRYPT            0x00000100UL
+#define CKF_DECRYPT            0x00000200UL
+#define CKF_DIGEST             0x00000400UL
+#define CKF_SIGN               0x00000800UL
+#define CKF_SIGN_RECOVER       0x00001000UL
+#define CKF_VERIFY             0x00002000UL
+#define CKF_VERIFY_RECOVER     0x00004000UL
+#define CKF_GENERATE           0x00008000UL
+#define CKF_GENERATE_KEY_PAIR  0x00010000UL
+#define CKF_WRAP               0x00020000UL
+#define CKF_UNWRAP             0x00040000UL
+#define CKF_DERIVE             0x00080000UL
+
+/* Describe a token's EC capabilities not available in mechanism
+ * information.
+ */
+#define CKF_EC_F_P             0x00100000UL
+#define CKF_EC_F_2M            0x00200000UL
+#define CKF_EC_ECPARAMETERS    0x00400000UL
+#define CKF_EC_NAMEDCURVE      0x00800000UL
+#define CKF_EC_UNCOMPRESS      0x01000000UL
+#define CKF_EC_COMPRESS        0x02000000UL
+
+#define CKF_EXTENSION          0x80000000UL
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function
+ */
+typedef CK_ULONG          CK_RV;
+
+#define CKR_OK                                0x00000000UL
+#define CKR_CANCEL                            0x00000001UL
+#define CKR_HOST_MEMORY                       0x00000002UL
+#define CKR_SLOT_ID_INVALID                   0x00000003UL
+
+#define CKR_GENERAL_ERROR                     0x00000005UL
+#define CKR_FUNCTION_FAILED                   0x00000006UL
+
+#define CKR_ARGUMENTS_BAD                     0x00000007UL
+#define CKR_NO_EVENT                          0x00000008UL
+#define CKR_NEED_TO_CREATE_THREADS            0x00000009UL
+#define CKR_CANT_LOCK                         0x0000000AUL
+
+#define CKR_ATTRIBUTE_READ_ONLY               0x00000010UL
+#define CKR_ATTRIBUTE_SENSITIVE               0x00000011UL
+#define CKR_ATTRIBUTE_TYPE_INVALID            0x00000012UL
+#define CKR_ATTRIBUTE_VALUE_INVALID           0x00000013UL
+
+#define CKR_ACTION_PROHIBITED                 0x0000001BUL
+
+#define CKR_DATA_INVALID                      0x00000020UL
+#define CKR_DATA_LEN_RANGE                    0x00000021UL
+#define CKR_DEVICE_ERROR                      0x00000030UL
+#define CKR_DEVICE_MEMORY                     0x00000031UL
+#define CKR_DEVICE_REMOVED                    0x00000032UL
+#define CKR_ENCRYPTED_DATA_INVALID            0x00000040UL
+#define CKR_ENCRYPTED_DATA_LEN_RANGE          0x00000041UL
+#define CKR_FUNCTION_CANCELED                 0x00000050UL
+#define CKR_FUNCTION_NOT_PARALLEL             0x00000051UL
+
+#define CKR_FUNCTION_NOT_SUPPORTED            0x00000054UL
+
+#define CKR_KEY_HANDLE_INVALID                0x00000060UL
+
+#define CKR_KEY_SIZE_RANGE                    0x00000062UL
+#define CKR_KEY_TYPE_INCONSISTENT             0x00000063UL
+
+#define CKR_KEY_NOT_NEEDED                    0x00000064UL
+#define CKR_KEY_CHANGED                       0x00000065UL
+#define CKR_KEY_NEEDED                        0x00000066UL
+#define CKR_KEY_INDIGESTIBLE                  0x00000067UL
+#define CKR_KEY_FUNCTION_NOT_PERMITTED        0x00000068UL
+#define CKR_KEY_NOT_WRAPPABLE                 0x00000069UL
+#define CKR_KEY_UNEXTRACTABLE                 0x0000006AUL
+
+#define CKR_MECHANISM_INVALID                 0x00000070UL
+#define CKR_MECHANISM_PARAM_INVALID           0x00000071UL
+
+#define CKR_OBJECT_HANDLE_INVALID             0x00000082UL
+#define CKR_OPERATION_ACTIVE                  0x00000090UL
+#define CKR_OPERATION_NOT_INITIALIZED         0x00000091UL
+#define CKR_PIN_INCORRECT                     0x000000A0UL
+#define CKR_PIN_INVALID                       0x000000A1UL
+#define CKR_PIN_LEN_RANGE                     0x000000A2UL
+
+#define CKR_PIN_EXPIRED                       0x000000A3UL
+#define CKR_PIN_LOCKED                        0x000000A4UL
+
+#define CKR_SESSION_CLOSED                    0x000000B0UL
+#define CKR_SESSION_COUNT                     0x000000B1UL
+#define CKR_SESSION_HANDLE_INVALID            0x000000B3UL
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED    0x000000B4UL
+#define CKR_SESSION_READ_ONLY                 0x000000B5UL
+#define CKR_SESSION_EXISTS                    0x000000B6UL
+
+#define CKR_SESSION_READ_ONLY_EXISTS          0x000000B7UL
+#define CKR_SESSION_READ_WRITE_SO_EXISTS      0x000000B8UL
+
+#define CKR_SIGNATURE_INVALID                 0x000000C0UL
+#define CKR_SIGNATURE_LEN_RANGE               0x000000C1UL
+#define CKR_TEMPLATE_INCOMPLETE               0x000000D0UL
+#define CKR_TEMPLATE_INCONSISTENT             0x000000D1UL
+#define CKR_TOKEN_NOT_PRESENT                 0x000000E0UL
+#define CKR_TOKEN_NOT_RECOGNIZED              0x000000E1UL
+#define CKR_TOKEN_WRITE_PROTECTED             0x000000E2UL
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID     0x000000F0UL
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE         0x000000F1UL
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT  0x000000F2UL
+#define CKR_USER_ALREADY_LOGGED_IN            0x00000100UL
+#define CKR_USER_NOT_LOGGED_IN                0x00000101UL
+#define CKR_USER_PIN_NOT_INITIALIZED          0x00000102UL
+#define CKR_USER_TYPE_INVALID                 0x00000103UL
+
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000104UL
+#define CKR_USER_TOO_MANY_TYPES               0x00000105UL
+
+#define CKR_WRAPPED_KEY_INVALID               0x00000110UL
+#define CKR_WRAPPED_KEY_LEN_RANGE             0x00000112UL
+#define CKR_WRAPPING_KEY_HANDLE_INVALID       0x00000113UL
+#define CKR_WRAPPING_KEY_SIZE_RANGE           0x00000114UL
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT    0x00000115UL
+#define CKR_RANDOM_SEED_NOT_SUPPORTED         0x00000120UL
+
+#define CKR_RANDOM_NO_RNG                     0x00000121UL
+
+#define CKR_DOMAIN_PARAMS_INVALID             0x00000130UL
+
+#define CKR_CURVE_NOT_SUPPORTED               0x00000140UL
+
+#define CKR_BUFFER_TOO_SMALL                  0x00000150UL
+#define CKR_SAVED_STATE_INVALID               0x00000160UL
+#define CKR_INFORMATION_SENSITIVE             0x00000170UL
+#define CKR_STATE_UNSAVEABLE                  0x00000180UL
+
+#define CKR_CRYPTOKI_NOT_INITIALIZED          0x00000190UL
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED      0x00000191UL
+#define CKR_MUTEX_BAD                         0x000001A0UL
+#define CKR_MUTEX_NOT_LOCKED                  0x000001A1UL
+
+#define CKR_NEW_PIN_MODE                      0x000001B0UL
+#define CKR_NEXT_OTP                          0x000001B1UL
+
+#define CKR_EXCEEDED_MAX_ITERATIONS           0x000001B5UL
+#define CKR_FIPS_SELF_TEST_FAILED             0x000001B6UL
+#define CKR_LIBRARY_LOAD_FAILED               0x000001B7UL
+#define CKR_PIN_TOO_WEAK                      0x000001B8UL
+#define CKR_PUBLIC_KEY_INVALID                0x000001B9UL
+
+#define CKR_FUNCTION_REJECTED                 0x00000200UL
+
+#define CKR_VENDOR_DEFINED                    0x80000000UL
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_NOTIFICATION   event,
+  CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions
+ */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+  CK_VOID_PTR_PTR ppMutex  /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize
+ */
+typedef struct CK_C_INITIALIZE_ARGS {
+  CK_CREATEMUTEX CreateMutex;
+  CK_DESTROYMUTEX DestroyMutex;
+  CK_LOCKMUTEX LockMutex;
+  CK_UNLOCKMUTEX UnlockMutex;
+  CK_FLAGS flags;
+  CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag                           Mask       Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL
+#define CKF_OS_LOCKING_OK                  0x00000002UL
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK     1
+
+/* CK_RSA_PKCS_MGF_TYPE  is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1         0x00000001UL
+#define CKG_MGF1_SHA256       0x00000002UL
+#define CKG_MGF1_SHA384       0x00000003UL
+#define CKG_MGF1_SHA512       0x00000004UL
+#define CKG_MGF1_SHA224       0x00000005UL
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED    0x00000001UL
+
+/* CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism.
+ */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+        CK_MECHANISM_TYPE hashAlg;
+        CK_RSA_PKCS_MGF_TYPE mgf;
+        CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+        CK_VOID_PTR pSourceData;
+        CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s).
+ */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+        CK_MECHANISM_TYPE    hashAlg;
+        CK_RSA_PKCS_MGF_TYPE mgf;
+        CK_ULONG             sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL                 0x00000001UL
+#define CKD_SHA1_KDF             0x00000002UL
+
+/* The following X9.42 DH key derivation functions are defined */
+#define CKD_SHA1_KDF_ASN1        0x00000003UL
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004UL
+#define CKD_SHA224_KDF           0x00000005UL
+#define CKD_SHA256_KDF           0x00000006UL
+#define CKD_SHA384_KDF           0x00000007UL
+#define CKD_SHA512_KDF           0x00000008UL
+#define CKD_CPDIVERSIFY_KDF      0x00000009UL
+
+
+/* CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+/*
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs.
+ */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms
+ */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair
+ */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs
+ */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism
+ */
+typedef struct CK_KEA_DERIVE_PARAMS {
+  CK_BBOOL      isSender;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pRandomB;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms.  An instance of CK_RC2_PARAMS just
+ * holds the effective keysize
+ */
+typedef CK_ULONG          CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism
+ */
+typedef struct CK_RC2_CBC_PARAMS {
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+  CK_BYTE       iv[8];            /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+  CK_ULONG      ulMacLength;      /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms
+ */
+typedef struct CK_RC5_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism
+ */
+typedef struct CK_RC5_CBC_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+  CK_BYTE_PTR   pIv;         /* pointer to IV */
+  CK_ULONG      ulIvLen;     /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulWordsize;   /* wordsize in bits */
+  CK_ULONG      ulRounds;     /* number of rounds */
+  CK_ULONG      ulMacLength;  /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms.  Its value is the length of
+ * the MAC
+ */
+typedef CK_ULONG          CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[8];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[16];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism
+ */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+  CK_ULONG      ulPasswordLen;
+  CK_BYTE_PTR   pPassword;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+  CK_ULONG      ulPAndGLen;
+  CK_ULONG      ulQLen;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pPrimeP;
+  CK_BYTE_PTR   pBaseG;
+  CK_BYTE_PTR   pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+  CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism
+ */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+  CK_ULONG      ulOldWrappedXLen;
+  CK_BYTE_PTR   pOldWrappedX;
+  CK_ULONG      ulOldPasswordLen;
+  CK_BYTE_PTR   pOldPassword;
+  CK_ULONG      ulOldPublicDataLen;
+  CK_BYTE_PTR   pOldPublicData;
+  CK_ULONG      ulOldRandomLen;
+  CK_BYTE_PTR   pOldRandomA;
+  CK_ULONG      ulNewPasswordLen;
+  CK_BYTE_PTR   pNewPassword;
+  CK_ULONG      ulNewPublicDataLen;
+  CK_BYTE_PTR   pNewPublicData;
+  CK_ULONG      ulNewRandomLen;
+  CK_BYTE_PTR   pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+  CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+  CK_BYTE_PTR      pInitVector;
+  CK_UTF8CHAR_PTR  pPassword;
+  CK_ULONG         ulPasswordLen;
+  CK_BYTE_PTR      pSalt;
+  CK_ULONG         ulSaltLen;
+  CK_ULONG         ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism
+ */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+  CK_BYTE       bBC;     /* block contents byte */
+  CK_BYTE_PTR   pX;      /* extra data */
+  CK_ULONG      ulXLen;  /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+typedef struct CK_SSL3_RANDOM_DATA {
+  CK_BYTE_PTR  pClientRandom;
+  CK_ULONG     ulClientRandomLen;
+  CK_BYTE_PTR  pServerRandom;
+  CK_ULONG     ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+  CK_SSL3_RANDOM_DATA RandomInfo;
+  CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hClientMacSecret;
+  CK_OBJECT_HANDLE hServerMacSecret;
+  CK_OBJECT_HANDLE hClientKey;
+  CK_OBJECT_HANDLE hServerKey;
+  CK_BYTE_PTR      pIVClient;
+  CK_BYTE_PTR      pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_BBOOL                bIsExport;
+  CK_SSL3_RANDOM_DATA     RandomInfo;
+  CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_PRF_PARAMS {
+  CK_BYTE_PTR  pSeed;
+  CK_ULONG     ulSeedLen;
+  CK_BYTE_PTR  pLabel;
+  CK_ULONG     ulLabelLen;
+  CK_BYTE_PTR  pOutput;
+  CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_RANDOM_DATA {
+  CK_BYTE_PTR pClientRandom;
+  CK_ULONG    ulClientRandomLen;
+  CK_BYTE_PTR pServerRandom;
+  CK_ULONG    ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+  CK_MECHANISM_TYPE   DigestMechanism;
+  CK_WTLS_RANDOM_DATA RandomInfo;
+  CK_BYTE_PTR         pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+  CK_MECHANISM_TYPE DigestMechanism;
+  CK_BYTE_PTR       pSeed;
+  CK_ULONG          ulSeedLen;
+  CK_BYTE_PTR       pLabel;
+  CK_ULONG          ulLabelLen;
+  CK_BYTE_PTR       pOutput;
+  CK_ULONG_PTR      pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hMacSecret;
+  CK_OBJECT_HANDLE hKey;
+  CK_BYTE_PTR      pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+  CK_MECHANISM_TYPE       DigestMechanism;
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_ULONG                ulSequenceNumber;
+  CK_BBOOL                bIsExport;
+  CK_WTLS_RANDOM_DATA     RandomInfo;
+  CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_CMS_SIG_PARAMS {
+  CK_OBJECT_HANDLE      certificateHandle;
+  CK_MECHANISM_PTR      pSigningMechanism;
+  CK_MECHANISM_PTR      pDigestMechanism;
+  CK_UTF8CHAR_PTR       pContentType;
+  CK_BYTE_PTR           pRequestedAttributes;
+  CK_ULONG              ulRequestedAttributesLen;
+  CK_BYTE_PTR           pRequiredAttributes;
+  CK_ULONG              ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+  CK_BYTE_PTR pData;
+  CK_ULONG    ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+  CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism.  It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key
+ */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR \
+                        CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+#define CKP_PKCS5_PBKD2_HMAC_SHA1          0x00000001UL
+#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411     0x00000002UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA224        0x00000003UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA256        0x00000004UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA384        0x00000005UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512        0x00000006UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_224    0x00000007UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_256    0x00000008UL
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR \
+                        CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED        0x00000001UL
+
+/* CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+        CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE           saltSource;
+        CK_VOID_PTR                                pSaltSourceData;
+        CK_ULONG                                   ulSaltSourceDataLen;
+        CK_ULONG                                   iterations;
+        CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+        CK_VOID_PTR                                pPrfData;
+        CK_ULONG                                   ulPrfDataLen;
+        CK_UTF8CHAR_PTR                            pPassword;
+        CK_ULONG_PTR                               ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PARAMS2 is a corrected version of the CK_PKCS5_PBKD2_PARAMS
+ * structure that provides the parameters to the CKM_PKCS5_PBKD2 mechanism
+ * noting that the ulPasswordLen field is a CK_ULONG and not a CK_ULONG_PTR.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS2 {
+        CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+        CK_VOID_PTR pSaltSourceData;
+        CK_ULONG ulSaltSourceDataLen;
+        CK_ULONG iterations;
+        CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+        CK_VOID_PTR pPrfData;
+        CK_ULONG ulPrfDataLen;
+        CK_UTF8CHAR_PTR pPassword;
+        CK_ULONG ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS2;
+
+typedef CK_PKCS5_PBKD2_PARAMS2 CK_PTR CK_PKCS5_PBKD2_PARAMS2_PTR;
+
+typedef CK_ULONG CK_OTP_PARAM_TYPE;
+typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* backward compatibility */
+
+typedef struct CK_OTP_PARAM {
+    CK_OTP_PARAM_TYPE type;
+    CK_VOID_PTR pValue;
+    CK_ULONG ulValueLen;
+} CK_OTP_PARAM;
+
+typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR;
+
+typedef struct CK_OTP_PARAMS {
+    CK_OTP_PARAM_PTR pParams;
+    CK_ULONG ulCount;
+} CK_OTP_PARAMS;
+
+typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR;
+
+typedef struct CK_OTP_SIGNATURE_INFO {
+    CK_OTP_PARAM_PTR pParams;
+    CK_ULONG ulCount;
+} CK_OTP_SIGNATURE_INFO;
+
+typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR;
+
+#define CK_OTP_VALUE          0UL
+#define CK_OTP_PIN            1UL
+#define CK_OTP_CHALLENGE      2UL
+#define CK_OTP_TIME           3UL
+#define CK_OTP_COUNTER        4UL
+#define CK_OTP_FLAGS          5UL
+#define CK_OTP_OUTPUT_LENGTH  6UL
+#define CK_OTP_OUTPUT_FORMAT  7UL
+
+#define CKF_NEXT_OTP          0x00000001UL
+#define CKF_EXCLUDE_TIME      0x00000002UL
+#define CKF_EXCLUDE_COUNTER   0x00000004UL
+#define CKF_EXCLUDE_CHALLENGE 0x00000008UL
+#define CKF_EXCLUDE_PIN       0x00000010UL
+#define CKF_USER_FRIENDLY_OTP 0x00000020UL
+
+typedef struct CK_KIP_PARAMS {
+    CK_MECHANISM_PTR  pMechanism;
+    CK_OBJECT_HANDLE  hKey;
+    CK_BYTE_PTR       pSeed;
+    CK_ULONG          ulSeedLen;
+} CK_KIP_PARAMS;
+
+typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR;
+
+typedef struct CK_AES_CTR_PARAMS {
+    CK_ULONG ulCounterBits;
+    CK_BYTE cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
+
+typedef struct CK_GCM_PARAMS {
+    CK_BYTE_PTR       pIv;
+    CK_ULONG          ulIvLen;
+    CK_ULONG          ulIvBits;
+    CK_BYTE_PTR       pAAD;
+    CK_ULONG          ulAADLen;
+    CK_ULONG          ulTagBits;
+} CK_GCM_PARAMS;
+
+typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
+
+typedef struct CK_CCM_PARAMS {
+    CK_ULONG          ulDataLen;
+    CK_BYTE_PTR       pNonce;
+    CK_ULONG          ulNonceLen;
+    CK_BYTE_PTR       pAAD;
+    CK_ULONG          ulAADLen;
+    CK_ULONG          ulMACLen;
+} CK_CCM_PARAMS;
+
+typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_GCM_PARAMS */
+typedef struct CK_AES_GCM_PARAMS {
+  CK_BYTE_PTR pIv;
+  CK_ULONG ulIvLen;
+  CK_ULONG ulIvBits;
+  CK_BYTE_PTR pAAD;
+  CK_ULONG ulAADLen;
+  CK_ULONG ulTagBits;
+} CK_AES_GCM_PARAMS;
+
+typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_CCM_PARAMS */
+typedef struct CK_AES_CCM_PARAMS {
+    CK_ULONG          ulDataLen;
+    CK_BYTE_PTR       pNonce;
+    CK_ULONG          ulNonceLen;
+    CK_BYTE_PTR       pAAD;
+    CK_ULONG          ulAADLen;
+    CK_ULONG          ulMACLen;
+} CK_AES_CCM_PARAMS;
+
+typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CTR_PARAMS {
+    CK_ULONG          ulCounterBits;
+    CK_BYTE           cb[16];
+} CK_CAMELLIA_CTR_PARAMS;
+
+typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS {
+    CK_BYTE           iv[16];
+    CK_BYTE_PTR       pData;
+    CK_ULONG          length;
+} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+                                CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS {
+    CK_BYTE           iv[16];
+    CK_BYTE_PTR       pData;
+    CK_ULONG          length;
+} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+                                CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_DSA_PARAMETER_GEN_PARAM {
+    CK_MECHANISM_TYPE  hash;
+    CK_BYTE_PTR        pSeed;
+    CK_ULONG           ulSeedLen;
+    CK_ULONG           ulIndex;
+} CK_DSA_PARAMETER_GEN_PARAM;
+
+typedef CK_DSA_PARAMETER_GEN_PARAM CK_PTR CK_DSA_PARAMETER_GEN_PARAM_PTR;
+
+typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS {
+    CK_ULONG           ulAESKeyBits;
+    CK_EC_KDF_TYPE     kdf;
+    CK_ULONG           ulSharedDataLen;
+    CK_BYTE_PTR        pSharedData;
+} CK_ECDH_AES_KEY_WRAP_PARAMS;
+
+typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN;
+
+typedef CK_ULONG CK_CERTIFICATE_CATEGORY;
+
+typedef struct CK_RSA_AES_KEY_WRAP_PARAMS {
+    CK_ULONG                      ulAESKeyBits;
+    CK_RSA_PKCS_OAEP_PARAMS_PTR   pOAEPParams;
+} CK_RSA_AES_KEY_WRAP_PARAMS;
+
+typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS {
+    CK_SSL3_RANDOM_DATA       RandomInfo;
+    CK_VERSION_PTR            pVersion;
+    CK_MECHANISM_TYPE         prfHashMechanism;
+} CK_TLS12_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+                                CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_TLS12_KEY_MAT_PARAMS {
+    CK_ULONG                  ulMacSizeInBits;
+    CK_ULONG                  ulKeySizeInBits;
+    CK_ULONG                  ulIVSizeInBits;
+    CK_BBOOL                  bIsExport;
+    CK_SSL3_RANDOM_DATA       RandomInfo;
+    CK_SSL3_KEY_MAT_OUT_PTR   pReturnedKeyMaterial;
+    CK_MECHANISM_TYPE         prfHashMechanism;
+} CK_TLS12_KEY_MAT_PARAMS;
+
+typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_KDF_PARAMS {
+    CK_MECHANISM_TYPE         prfMechanism;
+    CK_BYTE_PTR               pLabel;
+    CK_ULONG                  ulLabelLength;
+    CK_SSL3_RANDOM_DATA       RandomInfo;
+    CK_BYTE_PTR               pContextData;
+    CK_ULONG                  ulContextDataLength;
+} CK_TLS_KDF_PARAMS;
+
+typedef CK_TLS_KDF_PARAMS CK_PTR CK_TLS_KDF_PARAMS_PTR;
+
+typedef struct CK_TLS_MAC_PARAMS {
+    CK_MECHANISM_TYPE         prfHashMechanism;
+    CK_ULONG                  ulMacLength;
+    CK_ULONG                  ulServerOrClient;
+} CK_TLS_MAC_PARAMS;
+
+typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_DERIVE_PARAMS {
+    CK_EC_KDF_TYPE            kdf;
+    CK_BYTE_PTR               pPublicData;
+    CK_ULONG                  ulPublicDataLen;
+    CK_BYTE_PTR               pUKM;
+    CK_ULONG                  ulUKMLen;
+} CK_GOSTR3410_DERIVE_PARAMS;
+
+typedef CK_GOSTR3410_DERIVE_PARAMS CK_PTR CK_GOSTR3410_DERIVE_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_KEY_WRAP_PARAMS {
+    CK_BYTE_PTR               pWrapOID;
+    CK_ULONG                  ulWrapOIDLen;
+    CK_BYTE_PTR               pUKM;
+    CK_ULONG                  ulUKMLen;
+    CK_OBJECT_HANDLE          hKey;
+} CK_GOSTR3410_KEY_WRAP_PARAMS;
+
+typedef CK_GOSTR3410_KEY_WRAP_PARAMS CK_PTR CK_GOSTR3410_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS {
+    CK_BYTE                   iv[16];
+    CK_BYTE_PTR               pData;
+    CK_ULONG                  length;
+} CK_SEED_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_SEED_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+                                        CK_SEED_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+#endif /* _PKCS11T_H_ */
+
diff --git a/SoftHSMv2/src/lib/session_mgr/Makefile.am b/SoftHSMv2/src/lib/session_mgr/Makefile.am
new file mode 100644 (file)
index 0000000..5186d33
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES =                         $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                          -I$(srcdir)/.. \
+                                       -I$(srcdir)/../common \
+                                       -I$(srcdir)/../crypto \
+                                       -I$(srcdir)/../data_mgr \
+                                       -I$(srcdir)/../object_store \
+                                       -I$(srcdir)/../pkcs11 \
+                                       -I$(srcdir)/../slot_mgr
+
+noinst_LTLIBRARIES =                   libsofthsm_sessionmgr.la
+libsofthsm_sessionmgr_la_SOURCES =     SessionManager.cpp \
+                                       Session.cpp
+
+SUBDIRS =                              test
+
+EXTRA_DIST =                           $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/session_mgr/Session.cpp b/SoftHSMv2/src/lib/session_mgr/Session.cpp
new file mode 100644 (file)
index 0000000..5db36fd
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ Session.h
+
+ This class represents a single session
+ *****************************************************************************/
+
+#include "CryptoFactory.h"
+#include "Session.h"
+
+// Constructor
+Session::Session(Slot* inSlot, bool inIsReadWrite, CK_VOID_PTR inPApplication, CK_NOTIFY inNotify)
+{
+       slot = inSlot;
+       token = slot->getToken();
+       isReadWrite = inIsReadWrite;
+       hSession = CK_INVALID_HANDLE;
+       pApplication = inPApplication;
+       notify = inNotify;
+       operation = SESSION_OP_NONE;
+       findOp = NULL;
+       digestOp = NULL;
+       hashAlgo = HashAlgo::Unknown;
+       macOp = NULL;
+       asymmetricCryptoOp = NULL;
+       symmetricCryptoOp = NULL;
+       mechanism = AsymMech::Unknown;
+       reAuthentication = false;
+       allowSinglePartOp = false;
+       allowMultiPartOp = false;
+       publicKey = NULL;
+       privateKey = NULL;
+       symmetricKey = NULL;
+       param = NULL;
+       paramLen = 0;
+}
+
+// Constructor
+Session::Session()
+{
+       slot = NULL;
+       token = NULL;
+       isReadWrite = false;
+       hSession = CK_INVALID_HANDLE;
+       pApplication = NULL;
+       notify = NULL;
+       operation = SESSION_OP_NONE;
+       findOp = NULL;
+       digestOp = NULL;
+       hashAlgo = HashAlgo::Unknown;
+       macOp = NULL;
+       asymmetricCryptoOp = NULL;
+       symmetricCryptoOp = NULL;
+       mechanism = AsymMech::Unknown;
+       reAuthentication = false;
+       allowSinglePartOp = false;
+       allowMultiPartOp = false;
+       publicKey = NULL;
+       privateKey = NULL;
+       symmetricKey = NULL;
+       param = NULL;
+       paramLen = 0;
+}
+
+// Destructor
+Session::~Session()
+{
+       resetOp();
+}
+
+// Get session info
+CK_RV Session::getInfo(CK_SESSION_INFO_PTR pInfo)
+{
+       if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       pInfo->slotID = slot->getSlotID();
+
+       pInfo->state = getState();
+       pInfo->flags = CKF_SERIAL_SESSION;
+       if (isRW())
+       {
+               pInfo->flags |= CKF_RW_SESSION;
+       }
+       pInfo->ulDeviceError = 0;
+
+       return CKR_OK;
+}
+
+// Is a read and write session
+bool Session::isRW()
+{
+       return isReadWrite;
+}
+
+// Get session state
+CK_STATE Session::getState()
+{
+       if (token->isSOLoggedIn())
+       {
+               return CKS_RW_SO_FUNCTIONS;
+       }
+
+       if (token->isUserLoggedIn())
+       {
+               if (isRW())
+               {
+                       return CKS_RW_USER_FUNCTIONS;
+               }
+               else
+               {
+                       return CKS_RO_USER_FUNCTIONS;
+               }
+       }
+
+       if (isRW())
+       {
+               return CKS_RW_PUBLIC_SESSION;
+       }
+       else
+       {
+               return CKS_RO_PUBLIC_SESSION;
+       }
+}
+
+void Session::setHandle(CK_SESSION_HANDLE inHSession)
+{
+       hSession = inHSession;
+}
+
+CK_SESSION_HANDLE Session::getHandle()
+{
+       return hSession;
+}
+
+// Return the slot that the session is connected to
+Slot* Session::getSlot()
+{
+       return slot;
+}
+
+// Return the token that the session is connected to
+Token* Session::getToken()
+{
+       return token;
+}
+
+// Set the operation type
+void Session::setOpType(int inOperation)
+{
+       operation = inOperation;
+}
+
+// Get the operation type
+int Session::getOpType()
+{
+       return operation;
+}
+
+// Reset the operations
+void Session::resetOp()
+{
+       if (param != NULL)
+       {
+               free(param);
+               param = NULL;
+               paramLen = 0;
+       }
+
+       if (digestOp != NULL)
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(digestOp);
+               digestOp = NULL;
+       }
+       else if (findOp != NULL)
+       {
+               findOp->recycle();
+               findOp = NULL;
+       }
+       else if (asymmetricCryptoOp != NULL)
+       {
+               if (publicKey != NULL)
+               {
+                       asymmetricCryptoOp->recyclePublicKey(publicKey);
+                       publicKey = NULL;
+               }
+               if (privateKey != NULL)
+               {
+                       asymmetricCryptoOp->recyclePrivateKey(privateKey);
+                       privateKey = NULL;
+               }
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(asymmetricCryptoOp);
+               asymmetricCryptoOp = NULL;
+       }
+       else if (symmetricCryptoOp != NULL)
+       {
+               if (symmetricKey != NULL)
+               {
+                       symmetricCryptoOp->recycleKey(symmetricKey);
+                       symmetricKey = NULL;
+               }
+               CryptoFactory::i()->recycleSymmetricAlgorithm(symmetricCryptoOp);
+               symmetricCryptoOp = NULL;
+       }
+       else if (macOp != NULL)
+       {
+               if (symmetricKey != NULL)
+               {
+                       macOp->recycleKey(symmetricKey);
+                       symmetricKey = NULL;
+               }
+               CryptoFactory::i()->recycleMacAlgorithm(macOp);
+               macOp = NULL;
+       }
+
+       operation = SESSION_OP_NONE;
+       reAuthentication = false;
+}
+
+void Session::setFindOp(FindOperation *inFindOp)
+{
+       if (findOp != NULL) {
+               delete findOp;
+       }
+       findOp = inFindOp;
+}
+
+FindOperation *Session::getFindOp()
+{
+       return findOp;
+}
+
+// Set the digesting operator
+void Session::setDigestOp(HashAlgorithm* inDigestOp)
+{
+       if (digestOp != NULL)
+       {
+               CryptoFactory::i()->recycleHashAlgorithm(digestOp);
+       }
+
+       digestOp = inDigestOp;
+}
+
+// Get the digesting operator
+HashAlgorithm* Session::getDigestOp()
+{
+       return digestOp;
+}
+
+void Session::setHashAlgo(HashAlgo::Type inHashAlgo)
+{
+       hashAlgo = inHashAlgo;
+}
+
+HashAlgo::Type Session::getHashAlgo()
+{
+       return hashAlgo;
+}
+
+// Set the MACing operator
+void Session::setMacOp(MacAlgorithm *inMacOp)
+{
+       if (macOp != NULL)
+       {
+               setSymmetricKey(NULL);
+               CryptoFactory::i()->recycleMacAlgorithm(macOp);
+       }
+
+       macOp = inMacOp;
+}
+
+// Get the MACing operator
+MacAlgorithm *Session::getMacOp()
+{
+       return macOp;
+}
+
+void Session::setAsymmetricCryptoOp(AsymmetricAlgorithm *inAsymmetricCryptoOp)
+{
+       if (asymmetricCryptoOp != NULL)
+       {
+               setPublicKey(NULL);
+               setPrivateKey(NULL);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(asymmetricCryptoOp);
+       }
+
+       asymmetricCryptoOp = inAsymmetricCryptoOp;
+}
+
+AsymmetricAlgorithm *Session::getAsymmetricCryptoOp()
+{
+       return asymmetricCryptoOp;
+}
+
+void Session::setSymmetricCryptoOp(SymmetricAlgorithm *inSymmetricCryptoOp)
+{
+       if (symmetricCryptoOp != NULL)
+       {
+               setSymmetricKey(NULL);
+               CryptoFactory::i()->recycleSymmetricAlgorithm(symmetricCryptoOp);
+       }
+
+       symmetricCryptoOp = inSymmetricCryptoOp;
+}
+
+SymmetricAlgorithm *Session::getSymmetricCryptoOp()
+{
+       return symmetricCryptoOp;
+}
+
+void Session::setMechanism(AsymMech::Type inMechanism)
+{
+       mechanism = inMechanism;
+}
+
+AsymMech::Type Session::getMechanism()
+{
+       return mechanism;
+}
+
+void Session::setParameters(void* inParam, size_t inParamLen)
+{
+       if (inParam == NULL || inParamLen == 0) return;
+
+       if (param != NULL)
+       {
+               free(param);
+               paramLen = 0;
+       }
+
+       param = malloc(inParamLen);
+       if (param != NULL)
+       {
+               memcpy(param, inParam, inParamLen);
+               paramLen = inParamLen;
+       }
+}
+
+void* Session::getParameters(size_t& inParamLen)
+{
+       inParamLen = paramLen;
+       return param;
+}
+
+void Session::setReAuthentication(bool inReAuthentication)
+{
+       reAuthentication = inReAuthentication;
+}
+
+bool Session::getReAuthentication()
+{
+       return reAuthentication;
+}
+
+void Session::setAllowMultiPartOp(bool inAllowMultiPartOp)
+{
+       allowMultiPartOp = inAllowMultiPartOp;
+}
+
+bool Session::getAllowMultiPartOp()
+{
+       return allowMultiPartOp;
+}
+
+void Session::setAllowSinglePartOp(bool inAllowSinglePartOp)
+{
+       allowSinglePartOp = inAllowSinglePartOp;
+}
+
+bool Session::getAllowSinglePartOp()
+{
+       return allowSinglePartOp;
+}
+
+void Session::setPublicKey(PublicKey* inPublicKey)
+{
+       if (asymmetricCryptoOp == NULL)
+               return;
+
+       if (publicKey != NULL)
+       {
+               asymmetricCryptoOp->recyclePublicKey(publicKey);
+       }
+
+       publicKey = inPublicKey;
+}
+
+PublicKey* Session::getPublicKey()
+{
+       return publicKey;
+}
+
+void Session::setPrivateKey(PrivateKey* inPrivateKey)
+{
+       if (asymmetricCryptoOp == NULL)
+               return;
+
+       if (privateKey != NULL)
+       {
+               asymmetricCryptoOp->recyclePrivateKey(privateKey);
+       }
+
+       privateKey = inPrivateKey;
+}
+
+PrivateKey* Session::getPrivateKey()
+{
+       return privateKey;
+}
+
+void Session::setSymmetricKey(SymmetricKey* inSymmetricKey)
+{
+       if (symmetricKey != NULL)
+       {
+               if (macOp) {
+                       macOp->recycleKey(symmetricKey);
+               } else if (symmetricCryptoOp) {
+                       symmetricCryptoOp->recycleKey(symmetricKey);
+               } else {
+                       return;
+               }
+       }
+
+       symmetricKey = inSymmetricKey;
+}
+
+SymmetricKey* Session::getSymmetricKey()
+{
+       return symmetricKey;
+}
diff --git a/SoftHSMv2/src/lib/session_mgr/Session.h b/SoftHSMv2/src/lib/session_mgr/Session.h
new file mode 100644 (file)
index 0000000..142aaa5
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ Session.h
+
+ This class represents a single session
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSION_H
+#define _SOFTHSM_V2_SESSION_H
+
+#include "Slot.h"
+#include "FindOperation.h"
+#include "HashAlgorithm.h"
+#include "MacAlgorithm.h"
+#include "AsymmetricAlgorithm.h"
+#include "SymmetricAlgorithm.h"
+#include "Token.h"
+#include "cryptoki.h"
+
+#define SESSION_OP_NONE                        0x0
+#define SESSION_OP_FIND                        0x1
+#define SESSION_OP_ENCRYPT             0x2
+#define SESSION_OP_DECRYPT             0x3
+#define SESSION_OP_DIGEST              0x4
+#define SESSION_OP_SIGN                        0x5
+#define SESSION_OP_VERIFY              0x6
+#define SESSION_OP_DIGEST_ENCRYPT      0x7
+#define SESSION_OP_DECRYPT_DIGEST      0x8
+#define SESSION_OP_SIGN_ENCRYPT                0x9
+#define SESSION_OP_DECRYPT_VERIFY      0x10
+
+class Session
+{
+public:
+       Session(Slot* inSlot, bool inIsReadWrite, CK_VOID_PTR inPApplication, CK_NOTIFY inNotify);
+
+       // Destructor
+       virtual ~Session();
+
+       // Slot and token
+       Slot* getSlot();
+       Token* getToken();
+
+       // Session properties
+       CK_RV getInfo(CK_SESSION_INFO_PTR pInfo);
+       bool isRW();
+       CK_STATE getState();
+       void setHandle(CK_SESSION_HANDLE inHSession);
+       CK_SESSION_HANDLE getHandle();
+
+       // Operations
+       int getOpType();
+       void setOpType(int inOperation);
+       void resetOp();
+
+       // Find
+       void setFindOp(FindOperation *inFindOp);
+       FindOperation *getFindOp();
+
+       // Digest
+       void setDigestOp(HashAlgorithm* inDigestOp);
+       HashAlgorithm* getDigestOp();
+       void setHashAlgo(HashAlgo::Type inHashAlgo);
+       HashAlgo::Type getHashAlgo();
+
+       // Mac
+       void setMacOp(MacAlgorithm* inMacOp);
+       MacAlgorithm* getMacOp();
+
+       // Asymmetric Crypto
+       void setAsymmetricCryptoOp(AsymmetricAlgorithm* inAsymmetricCryptoOp);
+       AsymmetricAlgorithm* getAsymmetricCryptoOp();
+
+       // Symmetric Crypto
+       void setSymmetricCryptoOp(SymmetricAlgorithm* inSymmetricCryptoOp);
+       SymmetricAlgorithm* getSymmetricCryptoOp();
+
+       void setMechanism(AsymMech::Type inMechanism);
+       AsymMech::Type getMechanism();
+
+       void setParameters(void* inParam, size_t inParamLen);
+       void* getParameters(size_t& inParamLen);
+
+       void setReAuthentication(bool inReAuthentication);
+       bool getReAuthentication();
+
+       void setAllowMultiPartOp(bool inAllowMultiPartOp);
+       bool getAllowMultiPartOp();
+
+       void setAllowSinglePartOp(bool inAllowSinglePartOp);
+       bool getAllowSinglePartOp();
+
+       void setPublicKey(PublicKey* inPublicKey);
+       PublicKey* getPublicKey();
+
+       void setPrivateKey(PrivateKey* inPrivateKey);
+       PrivateKey* getPrivateKey();
+
+       void setSymmetricKey(SymmetricKey* inSymmetricKey);
+       SymmetricKey* getSymmetricKey();
+
+private:
+       // Constructor
+       Session();
+
+       // Slot and token
+       Slot* slot;
+       Token* token;
+
+       // Application data (not in use)
+       CK_VOID_PTR pApplication;
+       CK_NOTIFY notify;
+
+       // Session properties
+       bool isReadWrite;
+       CK_SESSION_HANDLE hSession;
+
+       // Operations
+       int operation;
+
+       // Find
+       FindOperation *findOp;
+
+       // Digest
+       HashAlgorithm* digestOp;
+       HashAlgo::Type hashAlgo;
+
+       // Mac
+       MacAlgorithm* macOp;
+
+       // Asymmetric Crypto
+       AsymmetricAlgorithm* asymmetricCryptoOp;
+
+       // Symmetric Crypto
+       SymmetricAlgorithm* symmetricCryptoOp;
+
+       AsymMech::Type mechanism;
+       void* param;
+       size_t paramLen;
+       bool reAuthentication;
+       bool allowMultiPartOp;
+       bool allowSinglePartOp;
+       PublicKey* publicKey;
+       PrivateKey* privateKey;
+
+       // Symmetric Crypto
+       SymmetricKey* symmetricKey;
+};
+
+#endif // !_SOFTHSM_V2_SESSION_H
diff --git a/SoftHSMv2/src/lib/session_mgr/SessionManager.cpp b/SoftHSMv2/src/lib/session_mgr/SessionManager.cpp
new file mode 100644 (file)
index 0000000..b665210
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionManager.cpp
+
+ Keeps track of the sessions within SoftHSM. The sessions are stored in a 
+ vector. When a session is closed, its spot in the vector will be replaced
+ with NULL. Because we want to keep track of the session ID which is 
+ equal to its location in the vector. New sessions will first fill up the NULL
+ locations and if there is no empty spots, then they are added to the end.
+ *****************************************************************************/
+
+#include "SessionManager.h"
+#include "log.h"
+
+// Constructor
+SessionManager::SessionManager()
+{
+       sessionsMutex = MutexFactory::i()->getMutex();
+}
+
+// Destructor
+SessionManager::~SessionManager()
+{
+       std::vector<Session*> toDelete = sessions;
+       sessions.clear();
+
+       for (std::vector<Session*>::iterator i = toDelete.begin(); i != toDelete.end(); i++)
+       {
+               if (*i != NULL) delete *i;
+       }
+
+       MutexFactory::i()->recycleMutex(sessionsMutex);
+}
+
+// Open a new session
+CK_RV SessionManager::openSession
+(
+       Slot* slot,
+       CK_FLAGS flags,
+       CK_VOID_PTR pApplication,
+       CK_NOTIFY notify,
+       CK_SESSION_HANDLE_PTR phSession
+)
+{
+       if (phSession == NULL_PTR) return CKR_ARGUMENTS_BAD;
+       if (slot == NULL) return CKR_SLOT_ID_INVALID;
+       if ((flags & CKF_SERIAL_SESSION) == 0) return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       // Get the token
+       Token* token = slot->getToken();
+       if (token == NULL) return CKR_TOKEN_NOT_PRESENT;
+       if (!token->isInitialized()) return CKR_TOKEN_NOT_RECOGNIZED;
+
+       // Can not open a Read-Only session when in SO mode
+       if ((flags & CKF_RW_SESSION) == 0 && token->isSOLoggedIn()) return CKR_SESSION_READ_WRITE_SO_EXISTS;
+
+       // TODO: Do we want to check for maximum number of sessions?
+       // return CKR_SESSION_COUNT
+
+       // Create the session
+       bool rwSession = ((flags & CKF_RW_SESSION) == CKF_RW_SESSION) ? true : false;
+       Session* session = new Session(slot, rwSession, pApplication, notify);
+
+       // First fill any empty spot in the list
+       for (size_t i = 0; i < sessions.size(); i++)
+       {
+               if (sessions[i] != NULL)
+               {
+                       continue;
+               }
+
+               sessions[i] = session;
+               session->setHandle(i + 1);
+               *phSession = session->getHandle();
+
+               return CKR_OK;
+       }
+
+       // Or add it to the end
+       sessions.push_back(session);
+       session->setHandle(sessions.size());
+       *phSession = session->getHandle();
+
+       return CKR_OK;
+}
+
+// Close a session
+CK_RV SessionManager::closeSession(CK_SESSION_HANDLE hSession)
+{
+       if (hSession == CK_INVALID_HANDLE) return CKR_SESSION_HANDLE_INVALID;
+
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       // Check if we are out of range
+       if (hSession > sessions.size()) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if it is a closed session
+       unsigned long sessionID = hSession - 1;
+       if (sessions[sessionID] == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       // Check if this is the last session on the token
+       bool lastSession = true;
+       const CK_SLOT_ID slotID( sessions[sessionID]->getSlot()->getSlotID() );
+       for (size_t i = 0; i < sessions.size(); i++)
+       {
+               if (sessions[i] == NULL) continue;
+
+               if (sessions[i]->getSlot()->getSlotID() == slotID && i != sessionID)
+               {
+                       lastSession = false;
+                       break;
+               }
+       }
+
+       // Logout if this is the last session on the token
+       if (lastSession)
+       {
+               sessions[sessionID]->getSlot()->getToken()->logout();
+       }
+
+       // Close the session
+       delete sessions[sessionID];
+       sessions[sessionID] = NULL;
+
+       return CKR_OK;
+}
+
+// Close all sessions
+CK_RV SessionManager::closeAllSessions(Slot* slot)
+{
+       if (slot == NULL) return CKR_SLOT_ID_INVALID;
+
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       // Get the token
+       Token* token = slot->getToken();
+       if (token == NULL) return CKR_TOKEN_NOT_PRESENT;
+
+       // Close all sessions on this slot
+       const CK_SLOT_ID slotID( slot->getSlotID() );
+       for (std::vector<Session*>::iterator i = sessions.begin(); i != sessions.end(); i++)
+       {
+               if (*i == NULL) continue;
+
+               if ((*i)->getSlot()->getSlotID() == slotID)
+               {
+                       delete *i;
+                       *i = NULL;
+               }
+       }
+
+       // Logout from the token
+       token->logout();
+
+       return CKR_OK;
+}
+
+// Get session info
+CK_RV SessionManager::getSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
+{
+       // Get the session
+       Session* session = getSession(hSession);
+       if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
+
+       return session->getInfo(pInfo);
+}
+
+// Get the session
+Session* SessionManager::getSession(CK_SESSION_HANDLE hSession)
+{
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       // We do not want to get a negative number below
+       if (hSession == CK_INVALID_HANDLE) return NULL;
+
+       // Check if we are out of range
+       if (hSession > sessions.size()) return NULL;
+
+       return sessions[hSession - 1];
+}
+
+bool SessionManager::haveSession(CK_SLOT_ID slotID)
+{
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       for (std::vector<Session*>::iterator i = sessions.begin(); i != sessions.end(); i++)
+       {
+               if (*i == NULL) continue;
+
+               if ((*i)->getSlot()->getSlotID() == slotID)
+               {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+bool SessionManager::haveROSession(CK_SLOT_ID slotID)
+{
+       // Lock access to the vector
+       MutexLocker lock(sessionsMutex);
+
+       for (std::vector<Session*>::iterator i = sessions.begin(); i != sessions.end(); i++)
+       {
+               if (*i == NULL) continue;
+
+               if ((*i)->getSlot()->getSlotID() != slotID) continue;
+
+               if ((*i)->isRW() == false) return true;
+       }
+
+       return false;
+}
diff --git a/SoftHSMv2/src/lib/session_mgr/SessionManager.h b/SoftHSMv2/src/lib/session_mgr/SessionManager.h
new file mode 100644 (file)
index 0000000..1091782
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionManager.h
+
+ Keeps track of the sessions within SoftHSM
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONMANAGER_H
+#define _SOFTHSM_V2_SESSIONMANAGER_H
+
+#include "Slot.h"
+#include "Session.h"
+#include "MutexFactory.h"
+#include "config.h"
+#include "cryptoki.h"
+#include <memory>
+#include <vector>
+
+class SessionManager
+{
+public:
+       SessionManager();
+
+       virtual ~SessionManager();
+
+       CK_RV openSession(Slot* slot, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession);
+       CK_RV closeSession(CK_SESSION_HANDLE hSession);
+       CK_RV closeAllSessions(Slot* slot);
+       CK_RV getSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo);
+       Session* getSession(CK_SESSION_HANDLE hSession);
+       bool haveSession(CK_SLOT_ID slotID);
+       bool haveROSession(CK_SLOT_ID slotID);
+
+private:
+       // The sessions
+       std::vector<Session*> sessions;
+       Mutex* sessionsMutex;
+};
+
+#endif // !_SOFTHSM_V2_SESSIONMANAGER_H
+
diff --git a/SoftHSMv2/src/lib/session_mgr/test/Makefile.am b/SoftHSMv2/src/lib/session_mgr/test/Makefile.am
new file mode 100644 (file)
index 0000000..6395038
--- /dev/null
@@ -0,0 +1,26 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../.. \
+                               -I$(srcdir)/../../common \
+                               -I$(srcdir)/../../crypto \
+                               -I$(srcdir)/../../data_mgr \
+                               -I$(srcdir)/../../object_store \
+                               -I$(srcdir)/../../pkcs11 \
+                               -I$(srcdir)/../../session_mgr \
+                               -I$(srcdir)/../../slot_mgr \
+                               @CPPUNIT_CFLAGS@ \
+                               @CRYPTO_INCLUDES@
+
+check_PROGRAMS =               sessionmgrtest
+
+sessionmgrtest_SOURCES =       sessionmgrtest.cpp \
+                               SessionManagerTests.cpp
+
+sessionmgrtest_LDADD =         ../../libsofthsm_convarch.la 
+
+sessionmgrtest_LDFLAGS =       @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread
+
+TESTS =                        sessionmgrtest
+
+EXTRA_DIST =                   $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.cpp b/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.cpp
new file mode 100644 (file)
index 0000000..2c2e51a
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionManagerTests.cpp
+
+ Contains test cases for SessionManager
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "SessionManagerTests.h"
+#include "ObjectStore.h"
+#include "SessionManager.h"
+#include "Session.h"
+#include "SlotManager.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SessionManagerTests);
+
+void SessionManagerTests::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void SessionManagerTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void SessionManagerTests::testOpenClose()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Create the managers
+       SlotManager slotManager(&store);
+       SessionManager sessionManager;
+
+       // Get a slot
+       CK_SLOT_ID slotID = 0;
+       Slot* slot = slotManager.getSlot(slotID);
+
+       // Use some bad data
+       CK_SESSION_HANDLE hSession;
+       CK_RV rv = sessionManager.openSession(NULL, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+       rv = sessionManager.openSession(slot, 0, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_PARALLEL_NOT_SUPPORTED);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, NULL_PTR);
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       // Try open a slot with an uninitialized token
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_TOKEN_NOT_RECOGNIZED);
+
+       // Initialize the token
+       ByteString soPIN((unsigned char*)"1234", 4);
+       CK_UTF8CHAR label[33] = "My test token                   ";
+       CPPUNIT_ASSERT(slot->initToken(soPIN, label) == CKR_OK);
+
+       // Open a session
+       bool haveSession = sessionManager.haveSession(slotID);
+       CPPUNIT_ASSERT(haveSession == false);
+       bool haveROSession = sessionManager.haveROSession(slotID);
+       CPPUNIT_ASSERT(haveROSession == false);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       haveSession = sessionManager.haveSession(slotID);
+       CPPUNIT_ASSERT(haveSession == true);
+       haveROSession = sessionManager.haveROSession(slotID);
+       CPPUNIT_ASSERT(haveROSession == true);
+
+       // Close session
+       rv = sessionManager.closeSession(CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       haveSession = sessionManager.haveSession(slotID);
+       CPPUNIT_ASSERT(haveSession == false);
+       haveROSession = sessionManager.haveROSession(slotID);
+       CPPUNIT_ASSERT(haveROSession == false);
+
+       // Try open a Read-Only session when in SO mode
+       rv = slot->getToken()->loginSO(soPIN);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_WRITE_SO_EXISTS);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       haveSession = sessionManager.haveSession(slotID);
+       CPPUNIT_ASSERT(haveSession == true);
+       haveROSession = sessionManager.haveROSession(slotID);
+       CPPUNIT_ASSERT(haveROSession == false);
+
+       // Close session and check that we are logged out
+       bool isLoggedIn = slot->getToken()->isSOLoggedIn();
+       CPPUNIT_ASSERT(isLoggedIn == true);
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       isLoggedIn = slot->getToken()->isSOLoggedIn();
+       CPPUNIT_ASSERT(isLoggedIn == false);
+       haveSession = sessionManager.haveSession(slotID);
+       CPPUNIT_ASSERT(haveSession == false);
+       haveROSession = sessionManager.haveROSession(slotID);
+       CPPUNIT_ASSERT(haveROSession == false);
+
+       // Open a new logged in session
+       rv = slot->getToken()->loginSO(soPIN);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close all sessions and check that we are logged out
+       isLoggedIn = slot->getToken()->isSOLoggedIn();
+       CPPUNIT_ASSERT(isLoggedIn == true);
+       rv = sessionManager.closeAllSessions(NULL);
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+       rv = sessionManager.closeAllSessions(slot);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       isLoggedIn = slot->getToken()->isSOLoggedIn();
+       CPPUNIT_ASSERT(isLoggedIn == false);
+}
+
+void SessionManagerTests::testSessionInfo()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Create the managers
+       SlotManager slotManager(&store);
+       SessionManager sessionManager;
+
+       // Get a slot
+       CK_SLOT_ID slotID = 0;
+       Slot* slot = slotManager.getSlot(slotID);
+
+       // Initialize the token
+       ByteString soPIN((unsigned char*)"1234", 4);
+       ByteString userPIN((unsigned char*)"1234", 4);
+       CK_UTF8CHAR label[33] = "My test token                   ";
+       CPPUNIT_ASSERT(slot->initToken(soPIN, label) == CKR_OK);
+       CPPUNIT_ASSERT(slot->getToken()->loginSO(soPIN) == CKR_OK);
+       CPPUNIT_ASSERT(slot->getToken()->initUserPIN(userPIN) == CKR_OK);
+       slot->getToken()->logout();
+
+       // Get a session
+       CK_SESSION_HANDLE hSession;
+       CK_RV rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get session info
+       CK_SESSION_INFO info;
+       rv = sessionManager.getSessionInfo(CK_INVALID_HANDLE, &info);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       rv = sessionManager.getSessionInfo(hSession, NULL_PTR);
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+       rv = sessionManager.getSessionInfo(hSession, &info);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Public RO session info
+       CPPUNIT_ASSERT(info.slotID == slotID);
+       CPPUNIT_ASSERT(info.state == CKS_RO_PUBLIC_SESSION);
+       CPPUNIT_ASSERT(info.flags == CKF_SERIAL_SESSION);
+
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Public RW session info
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       Session* session = sessionManager.getSession(CK_INVALID_HANDLE);
+       CPPUNIT_ASSERT(session == NULL);
+       session = sessionManager.getSession(hSession);
+       CPPUNIT_ASSERT(session != NULL);
+       rv = session->getInfo(&info);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(info.state == CKS_RW_PUBLIC_SESSION);
+       CPPUNIT_ASSERT(info.flags == (CKF_SERIAL_SESSION | CKF_RW_SESSION));
+
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // User RO session info
+       rv = slot->getToken()->loginUser(userPIN);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.getSessionInfo(hSession, &info);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(info.state == CKS_RO_USER_FUNCTIONS);
+       CPPUNIT_ASSERT(info.flags == CKF_SERIAL_SESSION);
+
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // User RW session info
+       rv = slot->getToken()->loginUser(userPIN);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.getSessionInfo(hSession, &info);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(info.state == CKS_RW_USER_FUNCTIONS);
+       CPPUNIT_ASSERT(info.flags == (CKF_SERIAL_SESSION | CKF_RW_SESSION));
+
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // SO RW session info
+       rv = slot->getToken()->loginSO(soPIN);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = sessionManager.getSessionInfo(hSession, &info);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(info.state == CKS_RW_SO_FUNCTIONS);
+       CPPUNIT_ASSERT(info.flags == (CKF_SERIAL_SESSION | CKF_RW_SESSION));
+
+       rv = sessionManager.closeSession(hSession);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
diff --git a/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.h b/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.h
new file mode 100644 (file)
index 0000000..23f9d8c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionManagerTests.h
+
+ Contains test cases for SessionManager
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONMANAGERTESTS_H
+#define _SOFTHSM_V2_SESSIONMANAGERTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SessionManagerTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(SessionManagerTests);
+       CPPUNIT_TEST(testOpenClose);
+       CPPUNIT_TEST(testSessionInfo);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testOpenClose();
+       void testSessionInfo();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_SESSIONMANAGERTESTS_H
diff --git a/SoftHSMv2/src/lib/session_mgr/test/sessionmgrtest.cpp b/SoftHSMv2/src/lib/session_mgr/test/sessionmgrtest.cpp
new file mode 100644 (file)
index 0000000..28eeee8
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ sessionmgrtest.cpp
+
+ The main test executor for tests on the session manager in SoftHSM v2
+ *****************************************************************************/
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Message.h>
+#include <cppunit/Exception.h>
+#include <cppunit/XmlOutputter.h>
+#include <fstream>
+#include <stdlib.h>
+#include <iostream>
+
+#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
+
+class MyListener : public CPPUNIT_NS::TestListener {
+        virtual void startTest( CPPUNIT_NS::Test*const pTest ) {
+                std::cout << std::endl << pTest->getName() << ' ' << pTest->countTestCases() << std::endl << std::endl;
+        }
+        virtual void addFailure( const CPPUNIT_NS::TestFailure & failure ) {
+                const CPPUNIT_NS::SourceLine solurceLine( failure.sourceLine() );
+                CPPUNIT_NS::Message message( failure.thrownException()->message() );
+                std::cout << solurceLine.fileName() << ' ' << solurceLine.lineNumber() << ' ' << message.shortDescription() << std::endl;
+                std::cout << message.details() << std::endl << std::endl;
+        }
+};
+
+int main(int /*argc*/, char** /*argv*/)
+{
+       CppUnit::TestResult controller;
+       CppUnit::TestResultCollector result;
+       CppUnit::TextUi::TestRunner runner;
+       controller.addListener(&result);
+       MyListener progress;
+       controller.addListener(&progress);
+       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;
+}
diff --git a/SoftHSMv2/src/lib/slot_mgr/Makefile.am b/SoftHSMv2/src/lib/slot_mgr/Makefile.am
new file mode 100644 (file)
index 0000000..1e8cf33
--- /dev/null
@@ -0,0 +1,18 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../common \
+                               -I$(srcdir)/../crypto \
+                               -I$(srcdir)/../data_mgr \
+                               -I$(srcdir)/../object_store \
+                               -I$(srcdir)/../pkcs11 \
+                               -I$(srcdir)/../session_mgr
+
+noinst_LTLIBRARIES =           libsofthsm_slotmgr.la
+libsofthsm_slotmgr_la_SOURCES =        SlotManager.cpp \
+                               Slot.cpp \
+                               Token.cpp
+
+SUBDIRS =                      test
+
+EXTRA_DIST =                   $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/slot_mgr/Slot.cpp b/SoftHSMv2/src/lib/slot_mgr/Slot.cpp
new file mode 100644 (file)
index 0000000..fea260b
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ Slot.h
+
+ This class represents a single PKCS #11 slot
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "SessionManager.h"
+#include "SlotManager.h"
+#include "Token.h"
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+
+// Constructor
+Slot::Slot(ObjectStore* inObjectStore, CK_SLOT_ID inSlotID, ObjectStoreToken* inToken /* = NULL */)
+{
+       objectStore = inObjectStore;
+       slotID = inSlotID;
+
+       if (inToken != NULL)
+       {
+               token = new Token(inToken);
+       }
+       else
+       {
+               token = new Token();
+       }
+}
+
+// Destructor
+Slot::~Slot()
+{
+       delete token;
+}
+
+// Retrieve the token in the slot
+Token* Slot::getToken()
+{
+       return token;
+}
+
+// Initialise the token in the slot
+CK_RV Slot::initToken(ByteString& soPIN, CK_UTF8CHAR_PTR label)
+{
+       return token->createToken(objectStore, soPIN, label);
+}
+
+// Retrieve slot information for the slot
+CK_RV Slot::getSlotInfo(CK_SLOT_INFO_PTR info)
+{
+       if (info == NULL)
+       {
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       std::ostringstream osDescription;
+       osDescription << "SoftHSM slot ID 0x" << std::hex << slotID;
+       const std::string sDescription(osDescription.str());
+
+       char mfgID[33];
+       snprintf(mfgID, 33, "SoftHSM project");
+
+       memset(info->slotDescription, ' ', 64);
+       memset(info->manufacturerID, ' ', 32);
+       memcpy(info->slotDescription, sDescription.data(), sDescription.size());
+       memcpy(info->manufacturerID, mfgID, strlen(mfgID));
+
+       info->flags = CKF_TOKEN_PRESENT;
+
+       info->hardwareVersion.major = VERSION_MAJOR;
+       info->hardwareVersion.minor = VERSION_MINOR;
+       info->firmwareVersion.major = VERSION_MAJOR;
+       info->firmwareVersion.minor = VERSION_MINOR;
+
+       return CKR_OK;
+}
+
+// Get the slot ID
+CK_SLOT_ID Slot::getSlotID()
+{
+       return slotID;
+}
+
+// Is a token present?
+bool Slot::isTokenPresent()
+{
+       return true;
+}
diff --git a/SoftHSMv2/src/lib/slot_mgr/Slot.h b/SoftHSMv2/src/lib/slot_mgr/Slot.h
new file mode 100644 (file)
index 0000000..6ab07c6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Slot.h
+
+ This class represents a single PKCS #11 slot
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SLOT_H
+#define _SOFTHSM_V2_SLOT_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "ObjectStore.h"
+#include "ObjectStoreToken.h"
+#include "Token.h"
+#include "cryptoki.h"
+#include <string>
+#include <vector>
+
+class Slot
+{
+public:
+       // Constructor
+       Slot(ObjectStore* inObjectStore, CK_SLOT_ID inSlotID, ObjectStoreToken *inToken = NULL);
+
+       // Destructor
+       virtual ~Slot();
+
+       // Retrieve the token in the slot
+       Token* getToken();
+
+       // Initialise the token in the slot
+       CK_RV initToken(ByteString& pin, CK_UTF8CHAR_PTR label);
+
+       // Retrieve slot information for the slot
+       CK_RV getSlotInfo(CK_SLOT_INFO_PTR info);
+
+       // Get the slot ID
+       CK_SLOT_ID getSlotID();
+
+       // Is a token present?
+       bool isTokenPresent();
+
+private:
+       // A reference to the object store
+       ObjectStore* objectStore;
+
+       // The token in the slot
+       Token* token;
+
+       // The slot ID
+       CK_SLOT_ID slotID;
+};
+
+#endif // !_SOFTHSM_V2_SLOT_H
+
diff --git a/SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp b/SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp
new file mode 100644 (file)
index 0000000..1f96909
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SlotManager.cpp
+
+ The slot manager is a class that forms part of the PKCS #11 core. It manages
+ all the slots that SoftHSM is aware of. To make it possible to add new
+ tokens, SoftHSM always has one slot available that contains an uninitialised
+ token. Users can choose to initialise this token to create a new token.
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "SlotManager.h"
+#include <cassert>
+#include <stdexcept>
+typedef std::pair<CK_SLOT_ID, Slot*> SlotMapElement;
+typedef std::pair<SlotMap::iterator, bool> InsertResult;
+
+// Constructor
+SlotManager::SlotManager(ObjectStore*const objectStore)
+{
+       // Add a slot for each token that already exists
+       for (size_t i = 0; i < objectStore->getTokenCount(); i++)
+       {
+               ObjectStoreToken*const pToken(objectStore->getToken(i));
+               ByteString bs;
+               pToken->getTokenSerial(bs);
+               const std::string s((const char*)bs.const_byte_str(), bs.size());
+
+               // parse serial string that is expected to have only hex digits.
+               CK_SLOT_ID l;
+               if (s.size() < 8)
+               {
+                       l = strtoul(s.c_str(), NULL, 16);
+               }
+               else
+               {
+                       l = strtoul(s.substr(s.size() - 8).c_str(), NULL, 16);
+               }
+
+               // mask for 31 bits.
+               // this since sunpkcs11 java wrapper is parsing the slot ID to a java int that needs to be positive.
+               // java int is 32 bit and the the sign bit is removed.
+               const CK_SLOT_ID mask( ((CK_SLOT_ID)1<<31)-1 );
+               const CK_SLOT_ID slotID(mask&l);
+
+               insertToken(objectStore, slotID, pToken);
+       }
+
+       // Add an empty slot
+       insertToken(objectStore, objectStore->getTokenCount(), NULL);
+}
+
+void SlotManager::insertToken(ObjectStore*const objectStore, const CK_SLOT_ID slotID, ObjectStoreToken*const pToken) {
+       Slot*const newSlot( new Slot(objectStore, slotID, pToken) );
+       const InsertResult result( slots.insert(SlotMapElement(slotID, newSlot)) );
+       assert(result.second);// fails if there is already a token on this slot
+}
+
+// Destructor
+SlotManager::~SlotManager()
+{
+       SlotMap toDelete = slots;
+       slots.clear();
+
+       for (SlotMap::iterator i = toDelete.begin(); i != toDelete.end(); i++)
+       {
+               delete i->second;
+       }
+}
+
+// Get the slot list
+CK_RV SlotManager::getSlotList(ObjectStore* objectStore, CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
+{
+       size_t size( 0 );
+
+       if (pulCount == NULL) return CKR_ARGUMENTS_BAD;
+
+       // Calculate the size of the list
+       bool uninitialized = false;
+       for (SlotMap::iterator i = slots.begin(); i != slots.end(); i++)
+       {
+               if ((tokenPresent == CK_FALSE) || i->second->isTokenPresent())
+               {
+                       size++;
+               }
+
+               if (i->second->getToken() != NULL && i->second->getToken()->isInitialized() == false)
+               {
+                       uninitialized = true;
+               }
+       }
+
+       // The user wants the size of the list
+       if (pSlotList == NULL)
+       {
+               // Always have an uninitialized token
+               if (uninitialized == false)
+               {
+                       insertToken(objectStore, objectStore->getTokenCount(), NULL);
+                       size++;
+               }
+
+               *pulCount = size;
+
+               return CKR_OK;
+       }
+
+       // Is the given buffer too small?
+       if (*pulCount < size)
+       {
+               *pulCount = size;
+
+               return CKR_BUFFER_TOO_SMALL;
+       }
+
+       size_t startIx( 0 );
+       size_t endIx( size-1 );
+
+       for (SlotMap::iterator i = slots.begin(); i != slots.end(); i++)
+       {
+               if ((tokenPresent == CK_TRUE) && !i->second->isTokenPresent())
+               {// only show token if present on slot. But this slot has no token so we continue
+                       continue;
+               }
+               // put uninitialized last. After all initialized or slots without tokens.
+               if ( i->second->isTokenPresent() && !i->second->getToken()->isInitialized() ) {
+                       pSlotList[endIx--] =  i->second->getSlotID();
+               } else {
+                       pSlotList[startIx++] = i->second->getSlotID();
+               }
+       }
+       assert(startIx==endIx+1);
+       *pulCount = size;
+
+       return CKR_OK;
+}
+
+// Get the slots
+SlotMap SlotManager::getSlots()
+{
+       return slots;
+}
+
+// Get one slot
+Slot* SlotManager::getSlot(CK_SLOT_ID slotID)
+{
+       try {
+               return slots.at(slotID);
+       } catch( const std::out_of_range &oor) {
+               DEBUG_MSG("slotID is out of range: %s", oor.what());
+               return NULL_PTR;
+       }
+}
diff --git a/SoftHSMv2/src/lib/slot_mgr/SlotManager.h b/SoftHSMv2/src/lib/slot_mgr/SlotManager.h
new file mode 100644 (file)
index 0000000..04f51c0
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ SlotManager.h
+
+ The slot manager is a class that forms part of the PKCS #11 core. It manages
+ all the slots that SoftHSM is aware of. To make it possible to add new
+ tokens, SoftHSM always has one slot available that contains an uninitialised
+ token. Users can choose to initialise this token to create a new token.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SLOTMANAGER_H
+#define _SOFTHSM_V2_SLOTMANAGER_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "ObjectStore.h"
+#include "Slot.h"
+#include <string>
+#include <map>
+typedef std::map<const CK_SLOT_ID, Slot*const> SlotMap;
+
+class SlotManager
+{
+public:
+       // Constructor
+       SlotManager(ObjectStore* objectStore);
+
+       // Destructor
+       virtual ~SlotManager();
+
+       // Get the slots
+       SlotMap getSlots();
+
+       // Get the slot list
+       CK_RV getSlotList(ObjectStore* objectStore, CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount);
+
+       // Get one slot
+       Slot* getSlot(CK_SLOT_ID slotID);
+private:
+       void insertToken(ObjectStore* objectStore, CK_SLOT_ID slotID, ObjectStoreToken* pToken);
+       // The slots
+       SlotMap slots;
+};
+
+#endif // !_SOFTHSM_V2_SLOTMANAGER_H
+
diff --git a/SoftHSMv2/src/lib/slot_mgr/Token.cpp b/SoftHSMv2/src/lib/slot_mgr/Token.cpp
new file mode 100644 (file)
index 0000000..b4c9401
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "log.h"
+#include "ObjectStore.h"
+#include "Token.h"
+#include "OSAttribute.h"
+#include "ByteString.h"
+#include "SecureDataManager.h"
+#include <cstdio>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+// Constructor
+Token::Token()
+{
+       tokenMutex = MutexFactory::i()->getMutex();
+
+       token = NULL;
+       sdm = NULL;
+       valid = false;
+}
+
+// Constructor
+Token::Token(ObjectStoreToken* inToken)
+{
+       tokenMutex = MutexFactory::i()->getMutex();
+
+       token = inToken;
+
+       ByteString soPINBlob, userPINBlob;
+
+       valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+       sdm = new SecureDataManager(soPINBlob, userPINBlob);
+}
+
+// Destructor
+Token::~Token()
+{
+       if (sdm != NULL) delete sdm;
+
+       MutexFactory::i()->recycleMutex(tokenMutex);
+}
+
+// Check if the token is still valid
+bool Token::isValid()
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       return (valid && token->isValid());
+}
+
+// Check if the token is initialized
+bool Token::isInitialized()
+{
+       if (token == NULL) return false;
+
+       return true;
+}
+
+// Check if SO is logged in
+bool Token::isSOLoggedIn()
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return false;
+
+       return sdm->isSOLoggedIn();
+}
+
+// Check if user is logged in
+bool Token::isUserLoggedIn()
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return false;
+
+       return sdm->isUserLoggedIn();
+}
+
+// Login SO
+CK_RV Token::loginSO(ByteString& pin)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       // User cannot be logged in
+       if (sdm->isUserLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+       // SO cannot be logged in
+       if (sdm->isSOLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;
+
+       // Get token flags
+       if (!token->getTokenFlags(flags))
+       {
+               ERROR_MSG("Could not get the token flags");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Login
+       if (!sdm->loginSO(pin))
+       {
+               flags |= CKF_SO_PIN_COUNT_LOW;
+               token->setTokenFlags(flags);
+               return CKR_PIN_INCORRECT;
+       }
+
+       flags &= ~CKF_SO_PIN_COUNT_LOW;
+       token->setTokenFlags(flags);
+       return CKR_OK;
+}
+
+// Login user
+CK_RV Token::loginUser(ByteString& pin)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       // SO cannot be logged in
+       if (sdm->isSOLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+       // User cannot be logged in
+       if (sdm->isUserLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;
+
+       // The user PIN has to be initialized;
+       if (sdm->getUserPINBlob().size() == 0) return CKR_USER_PIN_NOT_INITIALIZED;
+
+       // Get token flags
+       if (!token->getTokenFlags(flags))
+       {
+               ERROR_MSG("Could not get the token flags");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Login
+       if (!sdm->loginUser(pin))
+       {
+               flags |= CKF_USER_PIN_COUNT_LOW;
+               token->setTokenFlags(flags);
+               return CKR_PIN_INCORRECT;
+       }
+
+       flags &= ~CKF_USER_PIN_COUNT_LOW;
+       token->setTokenFlags(flags);
+       return CKR_OK;
+}
+
+CK_RV Token::reAuthenticate(ByteString& pin)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       // Get token flags
+       if (!token->getTokenFlags(flags))
+       {
+               ERROR_MSG("Could not get the token flags");
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (sdm->isSOLoggedIn())
+       {
+               // Login
+               if (!sdm->reAuthenticateSO(pin))
+               {
+                       flags |= CKF_SO_PIN_COUNT_LOW;
+                       token->setTokenFlags(flags);
+                       return CKR_PIN_INCORRECT;
+               }
+               else
+               {
+                       flags &= ~CKF_SO_PIN_COUNT_LOW;
+                       token->setTokenFlags(flags);
+               }
+       }
+       else if (sdm->isUserLoggedIn())
+       {
+               // Login
+               if (!sdm->reAuthenticateUser(pin))
+               {
+                       flags |= CKF_USER_PIN_COUNT_LOW;
+                       token->setTokenFlags(flags);
+                       return CKR_PIN_INCORRECT;
+               }
+               else
+               {
+                       flags &= ~CKF_USER_PIN_COUNT_LOW;
+                       token->setTokenFlags(flags);
+               }
+       }
+       else
+       {
+               return CKR_OPERATION_NOT_INITIALIZED;
+       }
+
+       return CKR_OK;
+}
+
+// Logout any user on this token;
+void Token::logout()
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return;
+
+       sdm->logout();
+}
+
+// Change SO PIN
+CK_RV Token::setSOPIN(ByteString& oldPIN, ByteString& newPIN)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       // Get token flags
+       if (!token->getTokenFlags(flags))
+       {
+               ERROR_MSG("Could not get the token flags");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Verify oldPIN
+       SecureDataManager* verifier = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
+       bool result = verifier->loginSO(oldPIN);
+       delete verifier;
+       if (result == false)
+       {
+               flags |= CKF_SO_PIN_COUNT_LOW;
+               token->setTokenFlags(flags);
+               return CKR_PIN_INCORRECT;
+       }
+
+       if (sdm->setSOPIN(newPIN) == false) return CKR_GENERAL_ERROR;
+
+       // Save PIN to token file
+       if (token->setSOPIN(sdm->getSOPINBlob()) == false) return CKR_GENERAL_ERROR;
+
+       ByteString soPINBlob, userPINBlob;
+       valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+       flags &= ~CKF_SO_PIN_COUNT_LOW;
+       token->setTokenFlags(flags);
+
+       return CKR_OK;
+}
+
+// Change the user PIN
+CK_RV Token::setUserPIN(ByteString& oldPIN, ByteString& newPIN)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       // Check if user should stay logged in
+       bool stayLoggedIn = sdm->isUserLoggedIn();
+
+       // Get token flags
+       if (!token->getTokenFlags(flags))
+       {
+               ERROR_MSG("Could not get the token flags");
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Verify oldPIN
+       SecureDataManager* newSdm = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
+       if (newSdm->loginUser(oldPIN) == false)
+       {
+               flags |= CKF_USER_PIN_COUNT_LOW;
+               token->setTokenFlags(flags);
+               delete newSdm;
+               return CKR_PIN_INCORRECT;
+       }
+
+       // Set the new user PIN
+       if (newSdm->setUserPIN(newPIN) == false)
+       {
+               delete newSdm;
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Save PIN to token file
+       if (token->setUserPIN(newSdm->getUserPINBlob()) == false)
+       {
+               delete newSdm;
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Restore previous login state
+       if (!stayLoggedIn) newSdm->logout();
+
+       // Switch sdm
+       delete sdm;
+       sdm = newSdm;
+
+       ByteString soPINBlob, userPINBlob;
+       valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+       flags &= ~CKF_USER_PIN_COUNT_LOW;
+       token->setTokenFlags(flags);
+
+       return CKR_OK;
+}
+
+// Init the user PIN
+CK_RV Token::initUserPIN(ByteString& pin)
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+       if (sdm->setUserPIN(pin) == false) return CKR_GENERAL_ERROR;
+
+       // Save PIN to token file
+       if (token->setUserPIN(sdm->getUserPINBlob()) == false) return CKR_GENERAL_ERROR;
+
+       ByteString soPINBlob, userPINBlob;
+       valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+       return CKR_OK;
+}
+
+// Create a new token
+CK_RV Token::createToken(ObjectStore* objectStore, ByteString& soPIN, CK_UTF8CHAR_PTR label)
+{
+       CK_ULONG flags;
+
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (objectStore == NULL) return CKR_GENERAL_ERROR;
+       if (label == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+       // Convert the label
+       ByteString labelByteStr((const unsigned char*) label, 32);
+
+       if (token != NULL)
+       {
+               // Get token flags
+               if (!token->getTokenFlags(flags))
+               {
+                       ERROR_MSG("Could not get the token flags");
+                       return CKR_GENERAL_ERROR;
+               }
+
+               // Verify SO PIN
+               if (sdm->getSOPINBlob().size() > 0 && !sdm->loginSO(soPIN))
+               {
+                       flags |= CKF_SO_PIN_COUNT_LOW;
+                       token->setTokenFlags(flags);
+
+                       ERROR_MSG("Incorrect SO PIN");
+                       return CKR_PIN_INCORRECT;
+               }
+               flags &= ~CKF_SO_PIN_COUNT_LOW;
+               token->setTokenFlags(flags);
+
+               // Reset the token
+               if (!token->resetToken(labelByteStr))
+               {
+                       ERROR_MSG("Could not reset the token");
+                       return CKR_DEVICE_ERROR;
+               }
+       }
+       else
+       {
+               // Generate the SO PIN blob
+               SecureDataManager soPINBlobGen;
+
+               if (!soPINBlobGen.setSOPIN(soPIN))
+               {
+                       return CKR_GENERAL_ERROR;
+               }
+
+               // Create the token
+               ObjectStoreToken* newToken = objectStore->newToken(labelByteStr);
+
+               if (newToken == NULL)
+               {
+                       ERROR_MSG("Could not create the token");
+                       return CKR_DEVICE_ERROR;
+               }
+
+               // Set the SO PIN on the token
+               if (!newToken->setSOPIN(soPINBlobGen.getSOPINBlob()))
+               {
+                       ERROR_MSG("Failed to set SO PIN on new token");
+
+                       if (!objectStore->destroyToken(newToken))
+                       {
+                               ERROR_MSG("Failed to destroy incomplete token");
+                       }
+
+                       return CKR_DEVICE_ERROR;
+               }
+
+               token = newToken;
+       }
+
+       ByteString soPINBlob, userPINBlob;
+
+       valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+       if (sdm != NULL) delete sdm;
+       sdm = new SecureDataManager(soPINBlob, userPINBlob);
+
+       return CKR_OK;
+}
+
+// Retrieve token information for the token
+CK_RV Token::getTokenInfo(CK_TOKEN_INFO_PTR info)
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       ByteString label, serial;
+
+       if (info == NULL)
+       {
+               return CKR_ARGUMENTS_BAD;
+       }
+
+       memset(info->label, ' ', 32);
+       memset(info->serialNumber, ' ', 16);
+
+       // Token specific information
+       if (token)
+       {
+               if (!token->getTokenFlags(info->flags))
+               {
+                       ERROR_MSG("Could not get the token flags");
+                       return CKR_GENERAL_ERROR;
+               }
+
+               if (token->getTokenLabel(label))
+               {
+                       strncpy((char*) info->label, (char*) label.byte_str(), label.size());
+               }
+
+               if (token->getTokenSerial(serial))
+               {
+                       strncpy((char*) info->serialNumber, (char*) serial.byte_str(), serial.size());
+               }
+       }
+       else
+       {
+               info->flags =   CKF_RNG |
+                               CKF_LOGIN_REQUIRED |
+                               CKF_RESTORE_KEY_NOT_NEEDED |
+                               CKF_SO_PIN_LOCKED |
+                               CKF_SO_PIN_TO_BE_CHANGED;
+       }
+
+       // Information shared by all tokens
+       char mfgID[33];
+       char model[17];
+
+       snprintf(mfgID, 33, "SoftHSM project");
+       snprintf(model, 17, "SoftHSM v2");
+
+       memset(info->manufacturerID, ' ', 32);
+       memset(info->model, ' ', 16);
+       memcpy(info->manufacturerID, mfgID, strlen(mfgID));
+       memcpy(info->model, model, strlen(model));
+
+       // TODO: Can we set these?
+       info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
+       info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
+
+       info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
+       info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+       info->ulMaxPinLen = MAX_PIN_LEN;
+       info->ulMinPinLen = MIN_PIN_LEN;
+       info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
+       info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
+       info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
+       info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
+       info->hardwareVersion.major = VERSION_MAJOR;
+       info->hardwareVersion.minor = VERSION_MINOR;
+       info->firmwareVersion.major = VERSION_MAJOR;
+       info->firmwareVersion.minor = VERSION_MINOR;
+
+       // Current time
+       time_t rawtime;
+       time(&rawtime);
+       char dateTime[17];
+       strftime(dateTime, 17, "%Y%m%d%H%M%S00", gmtime(&rawtime));
+       memcpy(info->utcTime, dateTime, 16);
+
+               return CKR_OK;
+}
+
+// Create an object
+OSObject* Token::createObject()
+{
+       return token->createObject();
+}
+
+void Token::getObjects(std::set<OSObject *> &objects)
+{
+       token->getObjects(objects);
+}
+
+bool Token::decrypt(const ByteString &encrypted, ByteString &plaintext)
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return false;
+
+       return sdm->decrypt(encrypted,plaintext);
+}
+
+bool Token::encrypt(const ByteString &plaintext, ByteString &encrypted)
+{
+       // Lock access to the token
+       MutexLocker lock(tokenMutex);
+
+       if (sdm == NULL) return false;
+
+       return sdm->encrypt(plaintext,encrypted);
+}
diff --git a/SoftHSMv2/src/lib/slot_mgr/Token.h b/SoftHSMv2/src/lib/slot_mgr/Token.h
new file mode 100644 (file)
index 0000000..8f67433
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ Token.h
+
+ This class represents a single PKCS #11 token
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_TOKEN_H
+#define _SOFTHSM_V2_TOKEN_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "ObjectStore.h"
+#include "ObjectStoreToken.h"
+#include "SecureDataManager.h"
+#include "cryptoki.h"
+#include <string>
+#include <vector>
+
+class Token
+{
+public:
+       // Constructor
+       Token();
+       Token(ObjectStoreToken *inToken);
+
+       // Destructor
+       virtual ~Token();
+
+       // Create a new token
+       CK_RV createToken(ObjectStore* objectStore, ByteString& soPIN, CK_UTF8CHAR_PTR label);
+
+       // Is the token valid?
+       bool isValid();
+
+       // Is the token initialized?
+       bool isInitialized();
+
+       // Is SO or user logged in?
+       bool isSOLoggedIn();
+       bool isUserLoggedIn();
+
+       // Login
+       CK_RV loginSO(ByteString& pin);
+       CK_RV loginUser(ByteString& pin);
+
+       // Re-authentication
+       CK_RV reAuthenticate(ByteString& pin);
+
+       // Logout any user on this token;
+       void logout();
+
+       // Change PIN
+       CK_RV setSOPIN(ByteString& oldPIN, ByteString& newPIN);
+       CK_RV setUserPIN(ByteString& oldPIN, ByteString& newPIN);
+       CK_RV initUserPIN(ByteString& pin);
+
+       // Retrieve token information for the token
+       CK_RV getTokenInfo(CK_TOKEN_INFO_PTR info);
+
+       // Create object
+       OSObject *createObject();
+
+       // Insert all token objects into the given set.
+       void getObjects(std::set<OSObject *> &objects);
+
+       // Decrypt the supplied data
+       bool decrypt(const ByteString& encrypted, ByteString& plaintext);
+
+       // Encrypt the supplied data
+       bool encrypt(const ByteString& plaintext, ByteString& encrypted);
+
+private:
+       // Token validity
+       bool valid;
+
+       // A reference to the object store token
+       ObjectStoreToken* token;
+
+       // The secure data manager for this token
+       SecureDataManager* sdm;
+
+       Mutex* tokenMutex;
+};
+
+#endif // !_SOFTHSM_V2_TOKEN_H
+
diff --git a/SoftHSMv2/src/lib/slot_mgr/test/Makefile.am b/SoftHSMv2/src/lib/slot_mgr/test/Makefile.am
new file mode 100644 (file)
index 0000000..8e2d161
--- /dev/null
@@ -0,0 +1,25 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../.. \
+                               -I$(srcdir)/../../common \
+                               -I$(srcdir)/../../crypto \
+                               -I$(srcdir)/../../data_mgr \
+                               -I$(srcdir)/../../object_store \
+                               -I$(srcdir)/../../pkcs11 \
+                               -I$(srcdir)/../../session_mgr \
+                               @CPPUNIT_CFLAGS@ \
+                               @CRYPTO_INCLUDES@
+
+check_PROGRAMS =               slotmgrtest
+
+slotmgrtest_SOURCES =          slotmgrtest.cpp \
+                               SlotManagerTests.cpp
+
+slotmgrtest_LDADD =            ../../libsofthsm_convarch.la 
+
+slotmgrtest_LDFLAGS =          @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread
+
+TESTS =                        slotmgrtest
+
+EXTRA_DIST =                   $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.cpp b/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.cpp
new file mode 100644 (file)
index 0000000..c5f6687
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SlotManagerTests.cpp
+
+ Contains test cases to test the object store implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "SlotManagerTests.h"
+#include "SlotManager.h"
+#include "Token.h"
+#include "ObjectStore.h"
+#include "ObjectFile.h"
+#include "File.h"
+#include "Directory.h"
+#include "OSAttribute.h"
+#include "OSAttributes.h"
+#include "CryptoFactory.h"
+#include "cryptoki.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SlotManagerTests);
+
+void SlotManagerTests::setUp()
+{
+       CPPUNIT_ASSERT(!system("mkdir testdir"));
+}
+
+void SlotManagerTests::tearDown()
+{
+#ifndef _WIN32
+       CPPUNIT_ASSERT(!system("rm -rf testdir"));
+#else
+       CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul"));
+#endif
+}
+
+void SlotManagerTests::testNoExistingTokens()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Create the slot manager
+       SlotManager slotManager(&store);
+
+       CPPUNIT_ASSERT(slotManager.getSlots().size() == 1);
+
+       // Test C_GetSlotList
+       CK_SLOT_ID testList[10];
+       CK_ULONG ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+
+       ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotID() == testList[0]);
+
+       // Retrieve slot information about the first slot
+       CK_SLOT_INFO slotInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the first slot
+       CK_TOKEN_INFO tokenInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+}
+
+void SlotManagerTests::testExistingTokens()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Create two tokens
+       ByteString label1 = "DEADBEEF";
+       ByteString label2 = "DEADC0FFEE";
+
+       CPPUNIT_ASSERT(store.newToken(label1) != NULL);
+       CPPUNIT_ASSERT(store.newToken(label2) != NULL);
+
+       // Now attach the slot manager
+       SlotManager slotManager(&store);
+
+       CPPUNIT_ASSERT(slotManager.getSlots().size() == 3);
+
+       // Test C_GetSlotList
+       CK_SLOT_ID testList[10];
+       CK_ULONG ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+
+       ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotID() == testList[0]);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotID() == testList[1]);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getSlotID() == testList[2]);
+
+       // Retrieve slot information about the first slot
+       CK_SLOT_INFO slotInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the first slot
+       CK_TOKEN_INFO tokenInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, &label1[0], label1.size()) || 
+                      !memcmp(tokenInfo.label, &label2[0], label2.size()));
+
+       // Retrieve slot information about the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, &label1[0], label1.size()) || 
+                      !memcmp(tokenInfo.label, &label2[0], label2.size()));
+
+       // Retrieve slot information about the third slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the third slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+}
+
+void SlotManagerTests::testInitialiseTokenInLastSlot()
+{
+       {
+               // Create an empty object store
+#ifndef _WIN32
+               ObjectStore store("./testdir");
+#else
+               ObjectStore store(".\\testdir");
+#endif
+
+               // Create the slot manager
+               SlotManager slotManager(&store);
+
+               CPPUNIT_ASSERT(slotManager.getSlots().size() == 1);
+
+               // Test C_GetSlotList
+               CK_SLOT_ID testList[10];
+               CK_ULONG ulCount = 10;
+
+               CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+               CPPUNIT_ASSERT(ulCount == 1);
+
+               ulCount = 10;
+
+               CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+               CPPUNIT_ASSERT(ulCount == 1);
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotID() == testList[0]);
+
+               // Retrieve slot information about the first slot
+               CK_SLOT_INFO slotInfo;
+
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+               CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+               // Retrieve token information about the token in the first slot
+               CK_TOKEN_INFO tokenInfo;
+
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+               CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+
+               // Now initialise the token in the first slot
+               ByteString soPIN((unsigned char*)"1234", 4);
+               CK_UTF8CHAR label[33] = "My test token                   ";
+
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->initToken(soPIN, label) == CKR_OK);
+
+               // Retrieve slot information about the first slot
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+               CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+               // Retrieve token information about the token in the first slot
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+               CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+               CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+               CPPUNIT_ASSERT(!memcmp(tokenInfo.label, label, 32));
+       }
+
+       // Attach a fresh slot manager
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+       SlotManager slotManager(&store);
+
+       CPPUNIT_ASSERT(slotManager.getSlots().size() == 2);
+
+       // Test C_GetSlotList
+       CK_SLOT_ID testList[10];
+       CK_ULONG ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+
+       ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotID() == testList[0]);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotID() == testList[1]);
+
+       // Retrieve slot information about the first slot
+       CK_SLOT_INFO slotInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the first slot
+       CK_TOKEN_INFO tokenInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+
+       CK_UTF8CHAR label[33] = "My test token                   ";
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, label, 32));
+
+       // Retrieve slot information about the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+}
+
+void SlotManagerTests::testReinitialiseExistingToken()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Create two tokens
+       ByteString label1 = "DEADBEEF";
+       ByteString label2 = "DEADC0FFEE";
+
+       CPPUNIT_ASSERT(store.newToken(label1) != NULL);
+       CPPUNIT_ASSERT(store.newToken(label2) != NULL);
+
+       // Now attach the slot manager
+       SlotManager slotManager(&store);
+
+       CPPUNIT_ASSERT(slotManager.getSlots().size() == 3);
+
+       // Test C_GetSlotList
+       CK_SLOT_ID testList[10];
+       CK_ULONG ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+
+       ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotID() == testList[0]);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotID() == testList[1]);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getSlotID() == testList[2]);
+
+       // Retrieve slot information about the first slot
+       CK_SLOT_INFO slotInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the first slot
+       CK_TOKEN_INFO tokenInfo;
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, &label1[0], label1.size()) || 
+                      !memcmp(tokenInfo.label, &label2[0], label2.size()));
+
+       // Retrieve slot information about the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, &label1[0], label1.size()) || 
+                      !memcmp(tokenInfo.label, &label2[0], label2.size()));
+
+       // Retrieve slot information about the third slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the third slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+
+       // Now reinitialise the token in the second slot
+       ByteString soPIN((unsigned char*)"1234", 4);
+       CK_UTF8CHAR label[33] = "My test token                   ";
+
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->initToken(soPIN, label) == CKR_OK);
+
+       // Retrieve slot information about the first slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getSlotInfo(&slotInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT);
+
+       // Retrieve token information about the token in the first slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(!memcmp(tokenInfo.label, label, 32));
+}
+
+void SlotManagerTests::testUninitialisedToken()
+{
+       // Create an empty object store
+#ifndef _WIN32
+       ObjectStore store("./testdir");
+#else
+       ObjectStore store(".\\testdir");
+#endif
+
+       // Now attach the slot manager
+       SlotManager slotManager(&store);
+
+       CPPUNIT_ASSERT(slotManager.getSlots().size() == 1);
+
+       // Test C_GetSlotList
+       CK_SLOT_ID testList[10];
+       CK_ULONG ulCount = 10;
+
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+
+       // Initialise the token in the first slot
+       ByteString soPIN((unsigned char*)"1234", 4);
+       CK_UTF8CHAR label[33] = "My test token                   ";
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->initToken(soPIN, label) == CKR_OK);
+
+       // Check if a new slot is added
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 1);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, NULL_PTR, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, NULL_PTR, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+
+       // get new list
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+
+       // Retrieve token information about the tokens
+       CK_TOKEN_INFO tokenInfo;
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+
+       // Initialise the token in the second slot
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->initToken(soPIN, label) == CKR_OK);
+
+       // Check if a new slot is added
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 2);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_FALSE, NULL_PTR, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+       ulCount = 10;
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, NULL_PTR, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+
+       // get new list
+       CPPUNIT_ASSERT(slotManager.getSlotList(&store, CK_TRUE, testList, &ulCount) == CKR_OK);
+       CPPUNIT_ASSERT(ulCount == 3);
+
+       // Retrieve token information about the tokens
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[0]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[1]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken() != NULL);
+       CPPUNIT_ASSERT(slotManager.getSlots()[testList[2]]->getToken()->getTokenInfo(&tokenInfo) == CKR_OK);
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) != CKF_TOKEN_INITIALIZED);
+}
+
diff --git a/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h b/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h
new file mode 100644 (file)
index 0000000..8d4e57f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ SlotManagerTests.h
+
+ Contains test cases to test the slot manager implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SLOTMANAGERTESTS_H
+#define _SOFTHSM_V2_SLOTMANAGERTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SlotManagerTests : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE(SlotManagerTests);
+       CPPUNIT_TEST(testNoExistingTokens);
+       CPPUNIT_TEST(testExistingTokens);
+       CPPUNIT_TEST(testInitialiseTokenInLastSlot);
+       CPPUNIT_TEST(testReinitialiseExistingToken);
+       CPPUNIT_TEST(testUninitialisedToken);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testNoExistingTokens();
+       void testExistingTokens();
+       void testInitialiseTokenInLastSlot();
+       void testReinitialiseExistingToken();
+       void testUninitialisedToken();
+
+       void setUp();
+       void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_SLOTMANAGERTESTS_H
+
diff --git a/SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp b/SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp
new file mode 100644 (file)
index 0000000..4172b63
--- /dev/null
@@ -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.
+ */
+
+/*****************************************************************************
+ slotmgrtest.cpp
+
+ The main test executor for tests on the slot 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;
+}
diff --git a/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp b/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp
new file mode 100644 (file)
index 0000000..6f06a42
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymEncryptDecryptTests.cpp
+
+ Contains test cases for C_EncryptInit, C_Encrypt, C_DecryptInit, C_Decrypt
+ using asymmetrical algorithms (i.e., RSA)
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "AsymEncryptDecryptTests.h"
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AsymEncryptDecryptTests);
+
+CK_RV AsymEncryptDecryptTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BYTE pubExp[] = {0x01, 0x00, 0x01};
+       CK_BYTE subject[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bFalse, sizeof(bFalse) },
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) },
+               { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_SUBJECT, &subject[0], sizeof(subject) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_UNWRAP, &bFalse, sizeof(bFalse) }
+       };
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                                                        pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        &hPuk, &hPrk) );
+}
+
+void AsymEncryptDecryptTests::rsaEncryptDecrypt(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey)
+{
+       CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
+       CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, 1, NULL_PTR, 0 };
+       CK_BYTE plainText[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,0x0C, 0x0D, 0x0F };
+       CK_BYTE cipherText[256];
+       CK_ULONG ulCipherTextLen;
+       CK_BYTE recoveredText[256];
+       CK_ULONG ulRecoveredTextLen;
+       CK_RV rv;
+
+       if (mechanismType == CKM_RSA_PKCS_OAEP)
+       {
+               mechanism.pParameter = &oaepParams;
+               mechanism.ulParameterLen = sizeof(oaepParams);
+       }
+
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulCipherTextLen = sizeof(cipherText);
+       rv =CRYPTOKI_F_PTR( C_Encrypt(hSession,plainText,sizeof(plainText),cipherText,&ulCipherTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechanism,hPrivateKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulRecoveredTextLen = sizeof(recoveredText);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CPPUNIT_ASSERT(memcmp(plainText, &recoveredText[ulRecoveredTextLen-sizeof(plainText)], sizeof(plainText)) == 0);
+}
+
+// Check that RSA OAEP mechanism properly validates all input parameters
+void AsymEncryptDecryptTests::rsaOAEPParams(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey)
+{
+       // This is only supported combination of parameters
+       CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL_PTR, 0 };
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_OAEP, NULL, 0 };
+       CK_RV rv;
+
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       mechanism.pParameter = &oaepParams;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       mechanism.ulParameterLen = sizeof(oaepParams);
+
+       oaepParams.hashAlg = CKM_AES_CBC;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       oaepParams.hashAlg = CKM_SHA_1;
+       oaepParams.mgf = CKG_MGF1_SHA256;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       oaepParams.mgf = CKG_MGF1_SHA1;
+       oaepParams.source = CKZ_DATA_SPECIFIED - 1;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       oaepParams.source = CKZ_DATA_SPECIFIED;
+       oaepParams.pSourceData = &oaepParams;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       oaepParams.ulSourceDataLen = sizeof(oaepParams);
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+
+       oaepParams.pSourceData = NULL;
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD);
+}
+
+void AsymEncryptDecryptTests::testRsaEncryptDecrypt()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token public/private key pairs.
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPublicKey,hPrivateKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rsaOAEPParams(hSessionRO,hPublicKey);
+       rsaEncryptDecrypt(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey);
+       rsaEncryptDecrypt(CKM_RSA_X_509,hSessionRO,hPublicKey,hPrivateKey);
+       rsaEncryptDecrypt(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey);
+}
diff --git a/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h b/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h
new file mode 100644 (file)
index 0000000..0b8db04
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymEncryptDecryptTests.h
+
+ Contains test cases for C_EncryptInit, C_Encrypt, C_DecryptInit, C_Decrypt
+ using asymmetrical algorithms (i.e., RSA)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ASYMENCRYPTDECRYPTTESTS_H
+#define _SOFTHSM_V2_ASYMENCRYPTDECRYPTTESTS_H
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class AsymEncryptDecryptTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(AsymEncryptDecryptTests);
+       CPPUNIT_TEST(testRsaEncryptDecrypt);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testRsaEncryptDecrypt();
+
+protected:
+       CK_RV generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+       void rsaEncryptDecrypt(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey);
+       void rsaOAEPParams(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey);
+};
+
+#endif // !_SOFTHSM_V2_ASYMENCRYPTDECRYPTTESTS_H
diff --git a/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp b/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp
new file mode 100644 (file)
index 0000000..9614e69
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014 Red Hat
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymWrapUnwrapTests.cpp
+
+ Contains test cases for C_WrapKey and C_UnwrapKey
+ using asymmetrical algorithms (RSA)
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "AsymWrapUnwrapTests.h"
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AsymWrapUnwrapTests);
+
+// Generate throw-away (session) symmetric key
+CK_RV AsymWrapUnwrapTests::generateAesKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_ULONG bytes = 16;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bFalse, sizeof(bTrue) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_VALUE_LEN, &bytes, sizeof(bytes) },
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+CK_RV AsymWrapUnwrapTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BYTE pubExp[] = {0x01, 0x00, 0x01};
+       CK_BYTE subject[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_VERIFY, &bFalse, sizeof(bFalse) },
+               { CKA_WRAP, &bTrue, sizeof(bTrue) },
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) },
+               { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_SUBJECT, &subject[0], sizeof(subject) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_SIGN, &bFalse, sizeof(bFalse) },
+               { CKA_UNWRAP, &bTrue, sizeof(bTrue) },
+       };
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                                                        pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        &hPuk, &hPrk) );
+}
+
+void AsymWrapUnwrapTests::rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey)
+{
+       CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
+       CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL_PTR, 0 };
+       CK_BYTE cipherText[2048];
+       CK_ULONG ulCipherTextLen;
+       CK_BYTE symValue[64];
+       CK_ULONG ulSymValueLen = sizeof(symValue);
+       CK_BYTE unwrappedValue[64];
+       CK_ULONG ulUnwrappedValueLen = sizeof(unwrappedValue);
+       CK_OBJECT_HANDLE symKey = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE unwrappedKey = CK_INVALID_HANDLE;
+       CK_RV rv;
+       CK_ULONG wrappedLenEstimation;
+
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_AES;
+       CK_ATTRIBUTE unwrapTemplate[] = {
+               { CKA_CLASS, &keyClass, sizeof(keyClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }
+       };
+
+       CK_ATTRIBUTE valueTemplate[] = {
+               { CKA_VALUE, &symValue, ulSymValueLen }
+       };
+
+       CK_MECHANISM_INFO mechInfo;
+
+       if (mechanismType == CKM_RSA_PKCS_OAEP)
+       {
+               mechanism.pParameter = &oaepParams;
+               mechanism.ulParameterLen = sizeof(oaepParams);
+       }
+
+       // Generate temporary symmetric key and remember it's value
+       rv = generateAesKey(hSession, symKey);
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, symKey, valueTemplate, sizeof(valueTemplate)/sizeof(CK_ATTRIBUTE)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       ulSymValueLen = valueTemplate[0].ulValueLen;
+
+       // CKM_RSA_PKCS Wrap/Unwrap support
+       rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, CKM_RSA_PKCS, &mechInfo) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       CPPUNIT_ASSERT(mechInfo.flags&CKF_WRAP);
+       CPPUNIT_ASSERT(mechInfo.flags&CKF_UNWRAP);
+
+       // Estimate wrapped length
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, symKey, NULL_PTR, &wrappedLenEstimation) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       CPPUNIT_ASSERT(wrappedLenEstimation>0);
+
+       // This should always fail because wrapped data have to be longer than 0 bytes
+       ulCipherTextLen = 0;
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, symKey, cipherText, &ulCipherTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_BUFFER_TOO_SMALL);
+
+       // Do real wrapping
+       ulCipherTextLen = sizeof(cipherText);
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, symKey, cipherText, &ulCipherTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       // Check length 'estimation'
+       CPPUNIT_ASSERT(wrappedLenEstimation>=ulCipherTextLen);
+
+       rv = CRYPTOKI_F_PTR( C_UnwrapKey(hSession, &mechanism, hPrivateKey, cipherText, ulCipherTextLen, unwrapTemplate, sizeof(unwrapTemplate)/sizeof(CK_ATTRIBUTE), &unwrappedKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       valueTemplate[0].pValue = &unwrappedValue;
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, unwrappedKey, valueTemplate, sizeof(valueTemplate)/sizeof(CK_ATTRIBUTE)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       ulUnwrappedValueLen = valueTemplate[0].ulValueLen;
+
+       CPPUNIT_ASSERT(ulSymValueLen == ulUnwrappedValueLen);
+       CPPUNIT_ASSERT(memcmp(symValue, unwrappedValue, ulSymValueLen) == 0);
+}
+
+void AsymWrapUnwrapTests::testRsaWrapUnwrap()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token public/private key pairs.
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPublicKey,hPrivateKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey);
+       rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey);
+}
diff --git a/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h b/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h
new file mode 100644 (file)
index 0000000..97f6940
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Red Hat
+ * 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.
+ */
+
+/*****************************************************************************
+ AsymWrapUnwrapTests.h
+
+ Contains test cases for C_WrapKey and C_UnwrapKey
+ using asymmetrical algorithms (RSA)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_ASYMWRAPUNWRAPTESTS_H
+#define _SOFTHSM_V2_ASYMWRAPUNWRAPTESTS_H
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class AsymWrapUnwrapTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(AsymWrapUnwrapTests);
+       CPPUNIT_TEST(testRsaWrapUnwrap);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testRsaWrapUnwrap();
+
+protected:
+       CK_RV generateAesKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+       void rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey);
+};
+
+#endif // !_SOFTHSM_V2_ASYMWRAPUNWRAPTESTS_H
diff --git a/SoftHSMv2/src/lib/test/DeriveTests.cpp b/SoftHSMv2/src/lib/test/DeriveTests.cpp
new file mode 100644 (file)
index 0000000..588d0b9
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2014 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ DeriveTests.cpp
+
+ Contains test cases for:
+        C_DeriveKey
+
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "DeriveTests.h"
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DeriveTests);
+
+CK_RV DeriveTests::generateDhKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_DH_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_BYTE bn1024[] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
+               0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
+               0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
+               0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
+               0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+               0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
+               0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
+               0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
+               0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
+               0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b,
+               0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
+               0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
+               0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
+               0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+       CK_BYTE bn2[] = { 2 };
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) },
+               { CKA_PRIME, &bn1024, sizeof(bn1024) },
+               { CKA_BASE, &bn2, sizeof(bn2) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                       pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                       prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                       &hPuk, &hPrk) );
+}
+
+#ifdef WITH_ECC
+CK_RV DeriveTests::generateEcKeyPair(const char* curve, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_KEY_TYPE keyType = CKK_EC;
+       CK_BYTE oidP256[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 };
+       CK_BYTE oidP384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 };
+       CK_BYTE oidP521[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 };
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_EC_PARAMS, NULL, 0 },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       /* Select the curve */
+       if (strcmp(curve, "P-256") == 0)
+       {
+               pukAttribs[0].pValue = oidP256;
+               pukAttribs[0].ulValueLen = sizeof(oidP256);
+       }
+       else if (strcmp(curve, "P-384") == 0)
+       {
+               pukAttribs[0].pValue = oidP384;
+               pukAttribs[0].ulValueLen = sizeof(oidP384);
+       }
+       else if (strcmp(curve, "P-521") == 0)
+       {
+               pukAttribs[0].pValue = oidP521;
+               pukAttribs[0].ulValueLen = sizeof(oidP521);
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                       pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                       prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                       &hPuk, &hPrk) );
+}
+#endif
+
+CK_RV DeriveTests::generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_ULONG bytes = 16;
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &bytes, sizeof(bytes) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+#ifndef WITH_FIPS
+CK_RV DeriveTests::generateDesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+#endif
+
+CK_RV DeriveTests::generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES2_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+CK_RV DeriveTests::generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES3_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DERIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+void DeriveTests::dhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey)
+{
+       CK_ATTRIBUTE valAttrib = { CKA_VALUE, NULL_PTR, 0 };
+       CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       valAttrib.pValue = (CK_BYTE_PTR)malloc(valAttrib.ulValueLen);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_MECHANISM mechanism = { CKM_DH_PKCS_DERIVE, NULL_PTR, 0 };
+       mechanism.pParameter = valAttrib.pValue;
+       mechanism.ulParameterLen = valAttrib.ulValueLen;
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ULONG secLen = 32;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_CLASS, &keyClass, sizeof(keyClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_PRIVATE, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &secLen, sizeof(secLen) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hPrivateKey,
+                        keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                        &hKey) );
+       free(valAttrib.pValue);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+#ifdef WITH_ECC
+void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw)
+{
+       CK_ATTRIBUTE valAttrib = { CKA_EC_POINT, NULL_PTR, 0 };
+       CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       valAttrib.pValue = (CK_BYTE_PTR)malloc(valAttrib.ulValueLen);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_ECDH1_DERIVE_PARAMS parms = { CKD_NULL, 0, NULL_PTR, 0, NULL_PTR };
+       // Use RAW or DER format
+       if (useRaw)
+       {
+               size_t offset = 0;
+               unsigned char* buf = (unsigned char*)valAttrib.pValue;
+               if (valAttrib.ulValueLen > 2 && buf[0] == 0x04)
+               {
+                       if (buf[1] < 0x80)
+                       {
+                               offset = 2;
+                       }
+                       else
+                       {
+                               if (valAttrib.ulValueLen > ((buf[1] & 0x7F) + (unsigned int)2))
+                               {
+                                       offset = 2 + (buf[1] & 0x7F);
+                               }
+                       }
+               }
+               parms.pPublicData = buf + offset;
+               parms.ulPublicDataLen = valAttrib.ulValueLen - offset;
+       }
+       else
+       {
+               parms.pPublicData = (unsigned char*)valAttrib.pValue;
+               parms.ulPublicDataLen = valAttrib.ulValueLen;
+       }
+
+       CK_MECHANISM mechanism = { CKM_ECDH1_DERIVE, NULL, 0 };
+       mechanism.pParameter = &parms;
+       mechanism.ulParameterLen = sizeof(parms);
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ULONG secLen = 32;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_CLASS, &keyClass, sizeof(keyClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_PRIVATE, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &secLen, sizeof(secLen) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hPrivateKey,
+                        keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                        &hKey) );
+       free(valAttrib.pValue);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+#endif
+
+bool DeriveTests::compareSecret(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey1, CK_OBJECT_HANDLE hKey2)
+{
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_VALUE, NULL_PTR, 0 },
+               { CKA_CHECK_VALUE, NULL_PTR, 0 }
+       };
+       CK_BYTE val1[128];
+       CK_BYTE check1[3];
+       keyAttribs[0].pValue = val1;
+       keyAttribs[0].ulValueLen = sizeof(val1);
+       keyAttribs[1].pValue = check1;
+       keyAttribs[1].ulValueLen = sizeof(check1);
+       CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hKey1, keyAttribs, 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(keyAttribs[0].ulValueLen == 32);
+       CPPUNIT_ASSERT(keyAttribs[1].ulValueLen == 3);
+       CK_BYTE val2[128];
+       CK_BYTE check2[3];
+       keyAttribs[0].pValue = val2;
+       keyAttribs[0].ulValueLen = sizeof(val2);
+       keyAttribs[1].pValue = check2;
+       keyAttribs[1].ulValueLen = sizeof(check2);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hKey2, keyAttribs, 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(keyAttribs[0].ulValueLen == 32);
+       CPPUNIT_ASSERT(keyAttribs[1].ulValueLen == 3);
+       return memcmp(val1, val2, 32) == 0 &&
+              memcmp(check1, check2, 3) == 0;
+}
+
+void DeriveTests::testDhDerive()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Public Session keys
+        CK_OBJECT_HANDLE hPuk1 = CK_INVALID_HANDLE;
+        CK_OBJECT_HANDLE hPrk1 = CK_INVALID_HANDLE;
+        CK_OBJECT_HANDLE hPuk2 = CK_INVALID_HANDLE;
+        CK_OBJECT_HANDLE hPrk2 = CK_INVALID_HANDLE;
+
+        rv = generateDhKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk1,hPrk1);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateDhKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk2,hPrk2);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_OBJECT_HANDLE hKey1 = CK_INVALID_HANDLE;
+       dhDerive(hSessionRW,hPuk1,hPrk2,hKey1);
+       CK_OBJECT_HANDLE hKey2 = CK_INVALID_HANDLE;
+       dhDerive(hSessionRW,hPuk2,hPrk1,hKey2);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Private Session Keys
+        rv = generateDhKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk1,hPrk1);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateDhKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk2,hPrk2);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+       dhDerive(hSessionRW,hPuk1,hPrk2,hKey1);
+       dhDerive(hSessionRW,hPuk2,hPrk1,hKey2);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Public Token Keys
+        rv = generateDhKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk1,hPrk1);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateDhKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk2,hPrk2);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+       dhDerive(hSessionRW,hPuk1,hPrk2,hKey1);
+       dhDerive(hSessionRW,hPuk2,hPrk1,hKey2);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Private Token Keys
+        rv = generateDhKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk1,hPrk1);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateDhKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk2,hPrk2);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+       dhDerive(hSessionRW,hPuk1,hPrk2,hKey1);
+       dhDerive(hSessionRW,hPuk2,hPrk1,hKey2);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+}
+
+#ifdef WITH_ECC
+void DeriveTests::testEcdhDerive()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Public Session keys
+       CK_OBJECT_HANDLE hPuk1 = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk1 = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPuk2 = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk2 = CK_INVALID_HANDLE;
+
+       rv = generateEcKeyPair("P-256",hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk1,hPrk1);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateEcKeyPair("P-256",hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk2,hPrk2);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_OBJECT_HANDLE hKey1 = CK_INVALID_HANDLE;
+       ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true);
+       CK_OBJECT_HANDLE hKey2 = CK_INVALID_HANDLE;
+       ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Private Session Keys
+       rv = generateEcKeyPair("P-384",hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk1,hPrk1);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateEcKeyPair("P-384",hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk2,hPrk2);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true);
+       ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Public Token Keys
+       rv = generateEcKeyPair("P-521",hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk1,hPrk1);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateEcKeyPair("P-521",hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk2,hPrk2);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true);
+       ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+
+       // Private Token Keys
+       rv = generateEcKeyPair("P-256",hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk1,hPrk1);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateEcKeyPair("P-256",hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk2,hPrk2);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true);
+       ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false);
+       CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2));
+}
+#endif
+
+void DeriveTests::symDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE &hDerive, CK_MECHANISM_TYPE mechType, CK_KEY_TYPE keyType)
+{
+       CK_RV rv;
+       CK_MECHANISM mechanism = { mechType, NULL_PTR, 0 };
+       CK_MECHANISM mechEncrypt = { CKM_VENDOR_DEFINED, NULL_PTR, 0 };
+       CK_KEY_DERIVATION_STRING_DATA param1;
+       CK_DES_CBC_ENCRYPT_DATA_PARAMS param2;
+       CK_AES_CBC_ENCRYPT_DATA_PARAMS param3;
+
+       CK_BYTE data[] = {
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+               0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+               0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24,
+               0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32
+       };
+       CK_ULONG secLen = 0;
+
+       switch (mechType)
+       {
+               case CKM_DES_ECB_ENCRYPT_DATA:
+               case CKM_DES3_ECB_ENCRYPT_DATA:
+               case CKM_AES_ECB_ENCRYPT_DATA:
+                       param1.pData = &data[0];
+                       param1.ulLen = sizeof(data);
+                       mechanism.pParameter = &param1;
+                       mechanism.ulParameterLen = sizeof(param1);
+                       break;
+               case CKM_DES_CBC_ENCRYPT_DATA:
+               case CKM_DES3_CBC_ENCRYPT_DATA:
+                       memcpy(param2.iv, "12345678", 8);
+                       param2.pData = &data[0];
+                       param2.length = sizeof(data);
+                       mechanism.pParameter = &param2;
+                       mechanism.ulParameterLen = sizeof(param2);
+                       break;
+               case CKM_AES_CBC_ENCRYPT_DATA:
+                       memcpy(param3.iv, "1234567890ABCDEF", 16);
+                       param3.pData = &data[0];
+                       param3.length = sizeof(data);
+                       mechanism.pParameter = &param3;
+                       mechanism.ulParameterLen = sizeof(param3);
+                       break;
+               default:
+                       CPPUNIT_FAIL("Invalid mechanism");
+       }
+
+       switch (keyType)
+       {
+               case CKK_GENERIC_SECRET:
+                       secLen = 32;
+                       break;
+               case CKK_DES:
+                       mechEncrypt.mechanism = CKM_DES_ECB;
+                       break;
+               case CKK_DES2:
+               case CKK_DES3:
+                       mechEncrypt.mechanism = CKM_DES3_ECB;
+                       break;
+               case CKK_AES:
+                       mechEncrypt.mechanism = CKM_AES_ECB;
+                       secLen = 32;
+                       break;
+               default:
+                       CPPUNIT_FAIL("Invalid key type");
+       }
+
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_CLASS, &keyClass, sizeof(keyClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_PRIVATE, &bFalse, sizeof(bFalse) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &secLen, sizeof(secLen) }
+       };
+
+       hDerive = CK_INVALID_HANDLE;
+       if (secLen > 0)
+       {
+               rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hKey,
+                                keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                                &hDerive) );
+       }
+       else
+       {
+               rv = CRYPTOKI_F_PTR( C_DeriveKey(hSession, &mechanism, hKey,
+                                keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE) - 1,
+                                &hDerive) );
+       }
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check that KCV has been set
+       CK_ATTRIBUTE checkAttribs[] = {
+               { CKA_CHECK_VALUE, NULL_PTR, 0 }
+       };
+       CK_BYTE check[3];
+       checkAttribs[0].pValue = check;
+       checkAttribs[0].ulValueLen = sizeof(check);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hDerive, checkAttribs, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(checkAttribs[0].ulValueLen == 3);
+
+       if (keyType == CKK_GENERIC_SECRET) return;
+
+       CK_BYTE cipherText[300];
+       CK_ULONG ulCipherTextLen;
+       CK_BYTE recoveredText[300];
+       CK_ULONG ulRecoveredTextLen;
+
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechEncrypt,hDerive) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulCipherTextLen = sizeof(cipherText);
+       rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,data,sizeof(data),cipherText,&ulCipherTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechEncrypt,hDerive) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulRecoveredTextLen = sizeof(recoveredText);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       CPPUNIT_ASSERT(ulRecoveredTextLen==sizeof(data));
+
+       CPPUNIT_ASSERT(memcmp(data, recoveredText, sizeof(data)) == 0);
+}
+
+void DeriveTests::testSymDerive()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Generate base key
+#ifndef WITH_FIPS
+        CK_OBJECT_HANDLE hKeyDes = CK_INVALID_HANDLE;
+#endif
+        CK_OBJECT_HANDLE hKeyDes2 = CK_INVALID_HANDLE;
+        CK_OBJECT_HANDLE hKeyDes3 = CK_INVALID_HANDLE;
+        CK_OBJECT_HANDLE hKeyAes = CK_INVALID_HANDLE;
+#ifndef WITH_FIPS
+        rv = generateDesKey(hSessionRW,IN_SESSION,IS_PUBLIC,hKeyDes);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+#endif
+        rv = generateDes2Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKeyDes2);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateDes3Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKeyDes3);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+        rv = generateAesKey(hSessionRW,IN_SESSION,IS_PUBLIC,hKeyAes);
+        CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Derive keys
+       CK_OBJECT_HANDLE hDerive = CK_INVALID_HANDLE;
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_ECB_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_ECB_ENCRYPT_DATA,CKK_DES);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_ECB_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_ECB_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_ECB_ENCRYPT_DATA,CKK_AES);
+#endif
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_AES);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_ECB_ENCRYPT_DATA,CKK_AES);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_ECB_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_ECB_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_ECB_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_ECB_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_ECB_ENCRYPT_DATA,CKK_AES);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_CBC_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_CBC_ENCRYPT_DATA,CKK_DES);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_CBC_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_CBC_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes,hDerive,CKM_DES_CBC_ENCRYPT_DATA,CKK_AES);
+#endif
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes2,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_AES);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyDes3,hDerive,CKM_DES3_CBC_ENCRYPT_DATA,CKK_AES);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_CBC_ENCRYPT_DATA,CKK_GENERIC_SECRET);
+#ifndef WITH_FIPS
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_CBC_ENCRYPT_DATA,CKK_DES);
+#endif
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_CBC_ENCRYPT_DATA,CKK_DES2);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_CBC_ENCRYPT_DATA,CKK_DES3);
+       symDerive(hSessionRW,hKeyAes,hDerive,CKM_AES_CBC_ENCRYPT_DATA,CKK_AES);
+}
+
diff --git a/SoftHSMv2/src/lib/test/DeriveTests.h b/SoftHSMv2/src/lib/test/DeriveTests.h
new file mode 100644 (file)
index 0000000..5b2aef5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ DeriveTests.h
+
+ Contains test cases to C_DeriveKey
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DERIVETESTS_H
+#define _SOFTHSM_V2_DERIVETESTS_H
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class DeriveTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(DeriveTests);
+       CPPUNIT_TEST(testDhDerive);
+#ifdef WITH_ECC
+       CPPUNIT_TEST(testEcdhDerive);
+#endif
+       CPPUNIT_TEST(testSymDerive);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testDhDerive();
+#ifdef WITH_ECC
+       void testEcdhDerive();
+#endif
+       void testSymDerive();
+
+protected:
+       CK_RV generateDhKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+       CK_RV generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+#ifndef WITH_FIPS
+       CK_RV generateDesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+#endif
+       CK_RV generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       void dhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey);
+#ifdef WITH_ECC
+       CK_RV generateEcKeyPair(const char* curve, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+       void ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw);
+#endif
+       bool compareSecret(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey1, CK_OBJECT_HANDLE hKey2);
+       void symDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE &hDerive, CK_MECHANISM_TYPE mechType, CK_KEY_TYPE keyType);
+};
+
+#endif // !_SOFTHSM_V2_DERIVETESTS_H
diff --git a/SoftHSMv2/src/lib/test/DigestTests.cpp b/SoftHSMv2/src/lib/test/DigestTests.cpp
new file mode 100644 (file)
index 0000000..b5e7e7e
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ DigestTests.cpp
+
+ Contains test cases to C_DigestInit, C_Digest, C_DigestUpdate, C_DigestFinal
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "DigestTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DigestTests);
+
+void DigestTests::testDigestInit()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_MECHANISM mechanism = {
+               CKM_VENDOR_DEFINED, NULL_PTR, 0
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(CK_INVALID_HANDLE, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_MECHANISM_INVALID);
+
+       mechanism.mechanism = CKM_SHA512;
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_ACTIVE);
+}
+
+void DigestTests::testDigest()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_MECHANISM mechanism = {
+               CKM_SHA512, NULL_PTR, 0
+       };
+       CK_ULONG digestLen;
+       CK_BYTE_PTR digest;
+       CK_BYTE data[] = {"Text to digest"};
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(CK_INVALID_HANDLE, data, sizeof(data)-1, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, NULL_PTR, sizeof(data)-1, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, NULL_PTR, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       digest = (CK_BYTE_PTR)malloc(digestLen);
+       digestLen = 0;
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, digest, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, digest, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, digest, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+       free(digest);
+}
+
+void DigestTests::testDigestUpdate()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_MECHANISM mechanism = {
+               CKM_SHA512, NULL_PTR, 0
+       };
+       CK_BYTE data[] = {"Text to digest"};
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(hSession, data, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(CK_INVALID_HANDLE, data, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(hSession, data, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(hSession, NULL_PTR, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(hSession, data, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void DigestTests::testDigestKey()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_MECHANISM mechanism = {
+               CKM_SHA512, NULL_PTR, 0
+       };
+       CK_BYTE data[] = {"Text to digest"};
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_DigestKey(hSession, (CK_OBJECT_HANDLE)123UL) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create the generic secret key to digest
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE genKeyType = CKK_GENERIC_SECRET;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_CLASS, &secretClass, sizeof(secretClass) },
+               { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_VALUE, data, sizeof(data) - 1 }
+       };
+       CK_OBJECT_HANDLE hKey;
+
+       hKey = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hKey != CK_INVALID_HANDLE);
+
+       rv = CRYPTOKI_F_PTR( C_DigestKey(CK_INVALID_HANDLE, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       
+       rv = CRYPTOKI_F_PTR( C_DigestKey(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestKey(hSession, CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_KEY_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_DigestKey(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void DigestTests::testDigestFinal()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_MECHANISM mechanism = {
+               CKM_SHA512, NULL_PTR, 0
+       };
+       CK_BYTE data[] = {"Text to digest"};
+       CK_ULONG digestLen;
+       CK_BYTE_PTR digest;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(CK_INVALID_HANDLE, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+       
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanism) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestUpdate(hSession, data, sizeof(data)-1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, NULL_PTR, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       digest = (CK_BYTE_PTR)malloc(digestLen);
+       digestLen = 0;
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, digest, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, digest, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       free(digest);
+
+       rv = CRYPTOKI_F_PTR( C_DigestFinal(hSession, NULL_PTR, &digestLen) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+}
+
+void DigestTests::testDigestAll()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_MECHANISM mechanisms[] = {
+#ifndef WITH_FIPS
+               { CKM_MD5, NULL_PTR, 0 },
+#endif
+               { CKM_SHA_1, NULL_PTR, 0 },
+               { CKM_SHA224, NULL_PTR, 0 },
+               { CKM_SHA256, NULL_PTR, 0 },
+               { CKM_SHA384, NULL_PTR, 0 },
+               { CKM_SHA512, NULL_PTR, 0 },
+#ifdef WITH_GOST
+               { CKM_GOSTR3411, NULL_PTR, 0 },
+#endif
+       };
+       CK_ULONG digestLen;
+       CK_BYTE_PTR digest;
+       CK_BYTE data[] = {"Text to digest"};
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       for (unsigned int i = 0; i < sizeof(mechanisms)/sizeof(CK_MECHANISM); i++)
+       {
+               rv = CRYPTOKI_F_PTR( C_DigestInit(hSession, &mechanisms[i]) );
+               CPPUNIT_ASSERT(rv == CKR_OK);
+
+               rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, NULL_PTR, &digestLen) );
+               CPPUNIT_ASSERT(rv == CKR_OK);
+
+               digest = (CK_BYTE_PTR)malloc(digestLen);
+
+               rv = CRYPTOKI_F_PTR( C_Digest(hSession, data, sizeof(data)-1, digest, &digestLen) );
+               CPPUNIT_ASSERT(rv == CKR_OK);
+               free(digest);
+       }
+}
diff --git a/SoftHSMv2/src/lib/test/DigestTests.h b/SoftHSMv2/src/lib/test/DigestTests.h
new file mode 100644 (file)
index 0000000..e724a39
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ DigestTests.h
+
+ Contains test cases to C_DigestInit, C_Digest, C_DigestUpdate, C_DigestFinal
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_DIGESTTESTS_H
+#define _SOFTHSM_V2_DIGESTTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class DigestTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(DigestTests);
+       CPPUNIT_TEST(testDigestInit);
+       CPPUNIT_TEST(testDigest);
+       CPPUNIT_TEST(testDigestUpdate);
+       CPPUNIT_TEST(testDigestKey);
+       CPPUNIT_TEST(testDigestFinal);
+       CPPUNIT_TEST(testDigestAll);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testDigestInit();
+       void testDigest();
+       void testDigestUpdate();
+       void testDigestKey();
+       void testDigestFinal();
+       void testDigestAll();
+};
+
+#endif // !_SOFTHSM_V2_DIGESTTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/InfoTests.cpp b/SoftHSMv2/src/lib/test/InfoTests.cpp
new file mode 100644 (file)
index 0000000..958d96e
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ InfoTests.cpp
+
+ Contains test cases to C_GetInfo, C_GetFunctionList, C_GetSlotList, 
+ C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, and C_GetMechanismInfo
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "InfoTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(InfoTests);
+
+void InfoTests::testGetInfo()
+{
+       CK_RV rv;
+       CK_INFO ckInfo;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetInfo(&ckInfo) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetInfo(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetInfo(&ckInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InfoTests::testGetFunctionList()
+{
+       CK_RV rv;
+       CK_FUNCTION_LIST_PTR ckFuncList;
+
+       rv = CRYPTOKI_F_PTR( C_GetFunctionList(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetFunctionList(&ckFuncList) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InfoTests::testGetSlotList()
+{
+       CK_RV rv;
+       CK_ULONG ulSlotCount = 0;
+       CK_SLOT_ID_PTR pSlotList;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_FALSE, NULL_PTR, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       // Get the size of the buffer
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       pSlotList = (CK_SLOT_ID_PTR)malloc(ulSlotCount * sizeof(CK_SLOT_ID));
+
+       // Check if we have a too small buffer
+       ulSlotCount = 0;
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       // Get the slot list
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       free(pSlotList);
+
+       // Get the number of slots with tokens
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       pSlotList = (CK_SLOT_ID_PTR)malloc(ulSlotCount * sizeof(CK_SLOT_ID));
+
+       // Check if we have a too small buffer
+       ulSlotCount = 0;
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, pSlotList, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       // Get the slot list
+       rv = CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, pSlotList, &ulSlotCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       free(pSlotList);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InfoTests::testGetSlotInfo()
+{
+       CK_RV rv;
+       CK_SLOT_INFO slotInfo;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_invalidSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT ) == CKF_TOKEN_PRESENT);
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_REMOVABLE_DEVICE ) == 0);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InfoTests::testGetSlotInfoAlt()
+{
+       CK_RV rv;
+       CK_SLOT_INFO slotInfo;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+#ifndef _WIN32
+    setenv("SOFTHSM2_CONF", "./softhsm2-alt.conf", 1);
+#else
+    setenv("SOFTHSM2_CONF", ".\\softhsm2-alt.conf", 1);
+#endif
+
+       CK_UTF8CHAR label[32];
+       memset(label, ' ', 32);
+       memcpy(label, "token1", strlen("token1"));
+
+       // (Re)initialize the token
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_invalidSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_GetSlotInfo(m_notInitializedTokenSlotID, &slotInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_TOKEN_PRESENT ) == CKF_TOKEN_PRESENT);
+       CPPUNIT_ASSERT((slotInfo.flags & CKF_REMOVABLE_DEVICE ) == CKF_REMOVABLE_DEVICE);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+#ifndef _WIN32
+       setenv("SOFTHSM2_CONF", "./softhsm2.conf", 1);
+#else
+       setenv("SOFTHSM2_CONF", ".\\softhsm2.conf", 1);
+#endif
+}
+
+
+void InfoTests::testGetTokenInfo()
+{
+       CK_RV rv;
+       CK_TOKEN_INFO tokenInfo;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_notInitializedTokenSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_notInitializedTokenSlotID, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_invalidSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_notInitializedTokenSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0);
+
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_initializedTokenSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InfoTests::testGetMechanismList()
+{
+       CK_RV rv;
+       CK_ULONG ulMechCount = 0;
+       CK_MECHANISM_TYPE_PTR pMechanismList;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, NULL_PTR, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, NULL_PTR, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_invalidSlotID, NULL_PTR, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       // Get the size of the buffer
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, NULL_PTR, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       pMechanismList = (CK_MECHANISM_TYPE_PTR)malloc(ulMechCount * sizeof(CK_MECHANISM_TYPE_PTR));
+
+       // Check if we have a too small buffer
+       ulMechCount = 0;
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, pMechanismList, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       // Get the mechanism list
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, pMechanismList, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       free(pMechanismList);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InfoTests::testGetMechanismInfo()
+{
+       CK_RV rv;
+       CK_MECHANISM_INFO info;
+       CK_ULONG ulMechCount = 0;
+       CK_MECHANISM_TYPE_PTR pMechanismList;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, CKM_RSA_PKCS, &info) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get the mechanism list
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, NULL_PTR, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(ulMechCount != 0);
+       pMechanismList = (CK_MECHANISM_TYPE_PTR)malloc(ulMechCount * sizeof(CK_MECHANISM_TYPE_PTR));
+       rv = CRYPTOKI_F_PTR( C_GetMechanismList(m_initializedTokenSlotID, pMechanismList, &ulMechCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, pMechanismList[0], NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_invalidSlotID, pMechanismList[0], &info) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, CKM_VENDOR_DEFINED, &info) );
+       CPPUNIT_ASSERT(rv == CKR_MECHANISM_INVALID);
+
+       for (unsigned int i = 0; i < ulMechCount; i++)
+       {
+               rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, pMechanismList[i], &info) );
+               CPPUNIT_ASSERT(rv == CKR_OK);
+       }
+
+       free(pMechanismList);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
diff --git a/SoftHSMv2/src/lib/test/InfoTests.h b/SoftHSMv2/src/lib/test/InfoTests.h
new file mode 100644 (file)
index 0000000..4acf770
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ InfoTests.h
+
+ Contains test cases to C_GetInfo, C_GetFunctionList, C_GetSlotList, 
+ C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, and C_GetMechanismInfo
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_INFOTESTS_H
+#define _SOFTHSM_V2_INFOTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class InfoTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(InfoTests);
+       CPPUNIT_TEST(testGetInfo);
+       CPPUNIT_TEST(testGetFunctionList);
+       CPPUNIT_TEST(testGetSlotList);
+       CPPUNIT_TEST(testGetSlotInfo);
+       CPPUNIT_TEST(testGetTokenInfo);
+       CPPUNIT_TEST(testGetMechanismList);
+       CPPUNIT_TEST(testGetMechanismInfo);
+       CPPUNIT_TEST(testGetSlotInfoAlt);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testGetInfo();
+       void testGetFunctionList();
+       void testGetSlotList();
+       void testGetSlotInfo();
+       void testGetTokenInfo();
+       void testGetMechanismList();
+       void testGetMechanismInfo();
+       void testGetSlotInfoAlt();
+};
+
+#endif // !_SOFTHSM_V2_INFOTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/InitTests.cpp b/SoftHSMv2/src/lib/test/InitTests.cpp
new file mode 100644 (file)
index 0000000..71611f8
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ InitTests.cpp
+
+ Contains test cases to C_Initialize and C_Finalize
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "InitTests.h"
+#include "cryptoki.h"
+#include "osmutex.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(InitTests);
+
+void InitTests::setUp()
+{
+//    printf("\nInitTests\n");
+
+#ifndef _WIN32
+       setenv("SOFTHSM2_CONF", "./softhsm2.conf", 1);
+#else
+       setenv("SOFTHSM2_CONF", ".\\softhsm2.conf", 1);
+#endif
+}
+
+void InitTests::tearDown()
+{
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
+
+void InitTests::testInit1()
+{
+       CK_RV rv;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testInit2()
+{
+       CK_C_INITIALIZE_ARGS InitArgs;
+       CK_RV rv;
+
+#ifdef CreateMutex
+#undef CreateMutex
+#endif
+
+       InitArgs.CreateMutex = NULL_PTR;
+       InitArgs.DestroyMutex = NULL_PTR;
+       InitArgs.LockMutex = NULL_PTR;
+       InitArgs.UnlockMutex = NULL_PTR;
+       InitArgs.flags = 0;
+       InitArgs.pReserved = (CK_VOID_PTR)1;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       InitArgs.pReserved = NULL_PTR;
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testInit3()
+{
+       CK_C_INITIALIZE_ARGS InitArgs;
+       CK_RV rv;
+
+       InitArgs.CreateMutex = NULL_PTR;
+       InitArgs.DestroyMutex = NULL_PTR;
+       InitArgs.LockMutex = NULL_PTR;
+       InitArgs.UnlockMutex = (CK_UNLOCKMUTEX)1;
+       InitArgs.flags = 0;
+       InitArgs.pReserved = NULL_PTR;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       InitArgs.UnlockMutex = NULL_PTR;
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testInit4()
+{
+       CK_C_INITIALIZE_ARGS InitArgs;
+       CK_RV rv;
+
+       InitArgs.CreateMutex = NULL_PTR;
+       InitArgs.DestroyMutex = NULL_PTR;
+       InitArgs.LockMutex = NULL_PTR;
+       InitArgs.UnlockMutex = (CK_UNLOCKMUTEX)1;
+       InitArgs.flags = CKF_OS_LOCKING_OK;
+       InitArgs.pReserved = NULL_PTR;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       InitArgs.UnlockMutex = NULL_PTR;
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       // If rv == CKR_CANT_LOCK then we cannot use multiple threads
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testInit5()
+{
+       CK_C_INITIALIZE_ARGS InitArgs;
+       CK_RV rv;
+
+       InitArgs.CreateMutex = OSCreateMutex;
+       InitArgs.DestroyMutex = OSDestroyMutex;
+       InitArgs.LockMutex = OSLockMutex;
+       InitArgs.UnlockMutex = NULL_PTR;
+       InitArgs.flags = 0;
+       InitArgs.pReserved = NULL_PTR;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       InitArgs.UnlockMutex = OSUnlockMutex;
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       // If rv == CKR_CANT_LOCK then we cannot use multiple threads
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testInit6()
+{
+       CK_C_INITIALIZE_ARGS InitArgs;
+       CK_RV rv;
+
+       InitArgs.CreateMutex = OSCreateMutex;
+       InitArgs.DestroyMutex = OSDestroyMutex;
+       InitArgs.LockMutex = OSLockMutex;
+       InitArgs.UnlockMutex = NULL_PTR;
+       InitArgs.flags = CKF_OS_LOCKING_OK;
+       InitArgs.pReserved = NULL_PTR;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       InitArgs.UnlockMutex = OSUnlockMutex;
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       // If rv == CKR_CANT_LOCK then we cannot use multiple threads
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize((CK_VOID_PTR)&InitArgs) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void InitTests::testFinal()
+{
+       CK_RV rv;
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // pReserved is reserved for future versions
+       rv = CRYPTOKI_F_PTR( C_Finalize((CK_VOID_PTR)1) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
diff --git a/SoftHSMv2/src/lib/test/InitTests.h b/SoftHSMv2/src/lib/test/InitTests.h
new file mode 100644 (file)
index 0000000..ba22ec0
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ InitTests.h
+
+ Contains test cases to C_Initialize and C_Finalize
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_INITTESTS_H
+#define _SOFTHSM_V2_INITTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "TestsNoPINInitBase.h"
+
+class InitTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(InitTests);
+       CPPUNIT_TEST(testInit1);
+       CPPUNIT_TEST(testInit2);
+       CPPUNIT_TEST(testInit3);
+       CPPUNIT_TEST(testInit4);
+       CPPUNIT_TEST(testInit5);
+       CPPUNIT_TEST(testInit6);
+       CPPUNIT_TEST(testFinal);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testInit1();
+       void testInit2();
+       void testInit3();
+       void testInit4();
+       void testInit5();
+       void testInit6();
+       void testFinal();
+
+       virtual void setUp();
+       virtual void tearDown();
+};
+
+#endif // !_SOFTHSM_V2_INITTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/Makefile.am b/SoftHSMv2/src/lib/test/Makefile.am
new file mode 100644 (file)
index 0000000..4345878
--- /dev/null
@@ -0,0 +1,40 @@
+MAINTAINERCLEANFILES =                 $(srcdir)/Makefile.in
+
+AM_CPPFLAGS =                  -I$(srcdir)/.. \
+                               -I$(srcdir)/../common \
+                               -I$(srcdir)/../pkcs11 \
+                               @CPPUNIT_CFLAGS@
+
+check_PROGRAMS =               p11test
+
+AUTOMAKE_OPTIONS =             subdir-objects
+
+p11test_SOURCES =              p11test.cpp \
+                               SymmetricAlgorithmTests.cpp \
+                               DigestTests.cpp \
+                               InitTests.cpp \
+                               InfoTests.cpp \
+                               RandomTests.cpp \
+                               SessionTests.cpp \
+                               TokenTests.cpp \
+                               UserTests.cpp \
+                               ObjectTests.cpp \
+                               DeriveTests.cpp \
+                               SignVerifyTests.cpp \
+                               AsymEncryptDecryptTests.cpp \
+                               AsymWrapUnwrapTests.cpp \
+                               TestsBase.cpp \
+                               TestsNoPINInitBase.cpp \
+                               ../common/log.cpp \
+                               ../common/osmutex.cpp
+
+p11test_LDADD =                        ../libsofthsm2.la 
+
+p11test_LDFLAGS =              @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread -static
+
+TESTS =                        p11test
+
+EXTRA_DIST =                   $(srcdir)/*.h \
+                               $(srcdir)/softhsm2-alt.conf.win32 \
+                               $(srcdir)/softhsm2.conf.win32 \
+                               $(srcdir)/tokens/dummy.in
diff --git a/SoftHSMv2/src/lib/test/ObjectTests.cpp b/SoftHSMv2/src/lib/test/ObjectTests.cpp
new file mode 100644 (file)
index 0000000..cd6c676
--- /dev/null
@@ -0,0 +1,2393 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ ObjectTests.cpp
+
+ Contains test cases for:
+        C_CreateObject
+        C_CopyObject
+        C_DestroyObject
+        C_GetAttributeValue
+        C_SetAttributeValue
+        C_FindObjectsInit
+        C_FindObjects
+        C_FindObjectsFinal
+        C_GenererateKeyPair
+
+ Below is a list of tests we need to add in order to verify that the PKCS#11 library
+ is working as expected.
+
+ We want to be sure that order of attributes does not impact the tests, therefore
+ every function involving attributes should have the order of the attributes
+ in the template randomized.
+
+ We want to be sure that only attributes that are specified as being part of an
+ object class can be used when creating an object.
+ Using other attributes should return an error on creation of the object.
+
+ We want to be sure that attributes that are required but missing will result
+ in a template incomplete return value.
+
+ We want to be sure that we get an error when trying to modify an attribute that
+ may not be modified
+
+ We want to be sure that attributes that may be changed to one value but not
+ back to the previous value are handled correctly.
+
+ We want to verify that an error is returned when we are trying to modify
+ read-only attributes.
+
+ We want to verify that sensitive attributes cannot be read.
+
+ Because the teardown also removes token objects it is not really
+ required to destroy objects created during the test in the CreateObject tests.
+
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ObjectTests.h"
+
+// Common object attributes
+const CK_BBOOL CKA_TOKEN_DEFAULT = CK_FALSE;
+//const CK_BBOOL CKA_PRIVATE_DEFAULT = <token/object attribute dependent>
+const CK_BBOOL CKA_MODIFIABLE_DEFAULT = CK_TRUE;
+const CK_UTF8CHAR_PTR CKA_LABEL_DEFAULT = NULL;
+const CK_BBOOL CKA_COPYABLE_DEFAULT = CK_TRUE;
+const CK_BBOOL CKA_DESTROYABLE_DEFAULT = CK_TRUE;
+
+// Data Object Attributes
+const CK_UTF8CHAR_PTR CKA_APPLICATION_DEFAULT = NULL;
+const CK_BYTE_PTR CKA_OBJECT_ID_DEFAULT = NULL;
+const CK_BYTE_PTR CKA_VALUE_DEFAULT = NULL;
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ObjectTests);
+
+void ObjectTests::checkCommonObjectAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_OBJECT_CLASS objClass)
+{
+       CK_RV rv;
+
+       CK_OBJECT_CLASS obj_class = CKO_VENDOR_DEFINED;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_CLASS, &obj_class, sizeof(obj_class) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(obj_class == objClass);
+}
+
+void ObjectTests::checkCommonStorageObjectAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BBOOL bToken, CK_BBOOL /*bPrivate*/, CK_BBOOL bModifiable, CK_UTF8CHAR_PTR pLabel, CK_ULONG ulLabelLen, CK_BBOOL bCopyable, CK_BBOOL bDestroyable)
+{
+       CK_RV rv;
+
+       CK_BBOOL obj_token = CK_FALSE;
+       CK_BBOOL obj_private = CK_FALSE;
+       CK_BBOOL obj_modifiable = CK_FALSE;
+       CK_BBOOL obj_copyable = CK_FALSE;
+       CK_BBOOL obj_destroyable = CK_FALSE;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_LABEL, NULL_PTR, 0 },
+               { CKA_TOKEN, &obj_token, sizeof(obj_token) },
+               { CKA_PRIVATE, &obj_private, sizeof(obj_private) },
+               { CKA_MODIFIABLE, &obj_modifiable, sizeof(obj_modifiable) },
+               { CKA_COPYABLE, &obj_copyable, sizeof(obj_copyable) },
+               { CKA_DESTROYABLE, &obj_destroyable, sizeof(obj_destroyable) }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 6) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulLabelLen);
+       CPPUNIT_ASSERT(obj_token == bToken);
+       /* Default is token-specifict
+       CPPUNIT_ASSERT(obj_private == bPrivate); */
+       CPPUNIT_ASSERT(obj_modifiable == bModifiable);
+       CPPUNIT_ASSERT(obj_copyable == bCopyable);
+       CPPUNIT_ASSERT(obj_destroyable == bDestroyable);
+       if (ulLabelLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pLabel, ulLabelLen) == 0);
+
+       free(attribs[0].pValue);
+}
+
+void ObjectTests::checkDataObjectAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_UTF8CHAR_PTR pApplication, CK_ULONG ulApplicationLen, CK_BYTE_PTR pObjectID, CK_ULONG ulObjectIdLen, CK_BYTE_PTR pValue, CK_ULONG ulValueLen)
+{
+       CK_RV rv;
+
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_APPLICATION, NULL_PTR, 0 },
+               { CKA_OBJECT_ID, NULL_PTR, 0 },
+               { CKA_VALUE, NULL_PTR, 0 }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 3) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+       attribs[1].pValue = (CK_VOID_PTR)malloc(attribs[1].ulValueLen);
+       attribs[2].pValue = (CK_VOID_PTR)malloc(attribs[2].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 3) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulApplicationLen);
+       CPPUNIT_ASSERT(attribs[1].ulValueLen == ulObjectIdLen);
+       CPPUNIT_ASSERT(attribs[2].ulValueLen == ulValueLen);
+       if (ulApplicationLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pApplication, ulApplicationLen) == 0);
+       if (ulObjectIdLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[1].pValue, pObjectID, ulObjectIdLen) == 0);
+       if (ulValueLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[2].pValue, pValue, ulValueLen) == 0);
+
+       free(attribs[0].pValue);
+       free(attribs[1].pValue);
+       free(attribs[2].pValue);
+}
+
+void ObjectTests::checkCommonCertificateObjectAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_CERTIFICATE_TYPE certType, CK_BBOOL bTrusted, CK_ULONG ulCertificateCategory, CK_BYTE_PTR pCheckValue, CK_ULONG ulCheckValueLen, CK_DATE startDate, CK_ULONG ulStartDateLen, CK_DATE endDate, CK_ULONG ulEndDateLen)
+{
+       CK_RV rv;
+
+       CK_CERTIFICATE_TYPE obj_type = CKC_X_509;
+       CK_BBOOL obj_trusted = CK_FALSE;
+       CK_ULONG obj_category = 0;
+       CK_DATE obj_start;
+       CK_DATE obj_end;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_CHECK_VALUE, NULL_PTR, 0 },
+               { CKA_CERTIFICATE_TYPE, &obj_type, sizeof(obj_type) },
+               { CKA_TRUSTED, &obj_trusted, sizeof(obj_trusted) },
+               { CKA_CERTIFICATE_CATEGORY, &obj_category, sizeof(obj_category) },
+               { CKA_START_DATE, &obj_start, sizeof(obj_start) },
+               { CKA_END_DATE, &obj_end, sizeof(obj_end) }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 6) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulCheckValueLen);
+       CPPUNIT_ASSERT(obj_type == certType);
+       CPPUNIT_ASSERT(obj_trusted == bTrusted);
+       CPPUNIT_ASSERT(obj_category == ulCertificateCategory);
+       CPPUNIT_ASSERT(attribs[4].ulValueLen == ulStartDateLen);
+       CPPUNIT_ASSERT(attribs[5].ulValueLen == ulEndDateLen);
+       if (ulCheckValueLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pCheckValue, ulCheckValueLen) == 0);
+       if (ulStartDateLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[4].pValue, &startDate, ulStartDateLen) == 0);
+       if (ulEndDateLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[5].pValue, &endDate, ulEndDateLen) == 0);
+
+       free(attribs[0].pValue);
+}
+
+void ObjectTests::checkX509CertificateObjectAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen, CK_BYTE_PTR pId, CK_ULONG ulIdLen, CK_BYTE_PTR pIssuer, CK_ULONG ulIssuerLen, CK_BYTE_PTR pSerialNumber, CK_ULONG ulSerialNumberLen, CK_BYTE_PTR pValue, CK_ULONG ulValueLen, CK_BYTE_PTR pUrl, CK_ULONG ulUrlLen, CK_BYTE_PTR pHashOfSubjectPublicKey, CK_ULONG ulHashOfSubjectPublicKeyLen, CK_BYTE_PTR pHashOfIssuerPublicKey, CK_ULONG ulHashOfIssuerPublicKeyLen, CK_ULONG ulJavaMidpSecurityDomain, CK_MECHANISM_TYPE nameHashAlgorithm)
+{
+       CK_RV rv;
+
+       CK_ULONG obj_java = 0;
+       CK_MECHANISM_TYPE obj_mech = CKM_VENDOR_DEFINED;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_SUBJECT, NULL_PTR, 0 },
+               { CKA_ID, NULL_PTR, 0 },
+               { CKA_ISSUER, NULL_PTR, 0 },
+               { CKA_SERIAL_NUMBER, NULL_PTR, 0 },
+               { CKA_VALUE, NULL_PTR, 0 },
+               { CKA_URL, NULL_PTR, 0 },
+               { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, NULL_PTR, 0 },
+               { CKA_HASH_OF_ISSUER_PUBLIC_KEY, NULL_PTR, 0 },
+               { CKA_JAVA_MIDP_SECURITY_DOMAIN, &obj_java, sizeof(obj_java) },
+               { CKA_NAME_HASH_ALGORITHM, &obj_mech, sizeof(obj_mech) }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 8) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+       attribs[1].pValue = (CK_VOID_PTR)malloc(attribs[1].ulValueLen);
+       attribs[2].pValue = (CK_VOID_PTR)malloc(attribs[2].ulValueLen);
+       attribs[3].pValue = (CK_VOID_PTR)malloc(attribs[3].ulValueLen);
+       attribs[4].pValue = (CK_VOID_PTR)malloc(attribs[4].ulValueLen);
+       attribs[5].pValue = (CK_VOID_PTR)malloc(attribs[5].ulValueLen);
+       attribs[6].pValue = (CK_VOID_PTR)malloc(attribs[6].ulValueLen);
+       attribs[7].pValue = (CK_VOID_PTR)malloc(attribs[7].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 10) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulSubjectLen);
+       CPPUNIT_ASSERT(attribs[1].ulValueLen == ulIdLen);
+       CPPUNIT_ASSERT(attribs[2].ulValueLen == ulIssuerLen);
+       CPPUNIT_ASSERT(attribs[3].ulValueLen == ulSerialNumberLen);
+       CPPUNIT_ASSERT(attribs[4].ulValueLen == ulValueLen);
+       CPPUNIT_ASSERT(attribs[5].ulValueLen == ulUrlLen);
+       CPPUNIT_ASSERT(attribs[6].ulValueLen == ulHashOfSubjectPublicKeyLen);
+       CPPUNIT_ASSERT(attribs[7].ulValueLen == ulHashOfIssuerPublicKeyLen);
+       CPPUNIT_ASSERT(obj_java == ulJavaMidpSecurityDomain);
+       CPPUNIT_ASSERT(obj_mech == nameHashAlgorithm);
+       if (ulSubjectLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pSubject, ulSubjectLen) == 0);
+       if (ulIdLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[1].pValue, pId, ulIdLen) == 0);
+       if (ulIssuerLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[2].pValue, pIssuer, ulIssuerLen) == 0);
+       if (ulSerialNumberLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[3].pValue, pSerialNumber, ulSerialNumberLen) == 0);
+       if (ulValueLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[4].pValue, pValue, ulValueLen) == 0);
+       if (ulUrlLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[5].pValue, pUrl, ulUrlLen) == 0);
+       if (ulHashOfSubjectPublicKeyLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[6].pValue, pHashOfSubjectPublicKey, ulHashOfSubjectPublicKeyLen) == 0);
+       if (ulHashOfIssuerPublicKeyLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[7].pValue, pHashOfIssuerPublicKey, ulHashOfIssuerPublicKeyLen) == 0);
+
+       free(attribs[0].pValue);
+       free(attribs[1].pValue);
+       free(attribs[2].pValue);
+       free(attribs[3].pValue);
+       free(attribs[4].pValue);
+       free(attribs[5].pValue);
+       free(attribs[6].pValue);
+       free(attribs[7].pValue);
+}
+
+void ObjectTests::checkCommonKeyAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_KEY_TYPE keyType, CK_BYTE_PTR pId, CK_ULONG ulIdLen, CK_DATE startDate, CK_ULONG ulStartDateLen, CK_DATE endDate, CK_ULONG ulEndDateLen, CK_BBOOL bDerive, CK_BBOOL bLocal, CK_MECHANISM_TYPE keyMechanismType, CK_MECHANISM_TYPE_PTR pAllowedMechanisms, CK_ULONG ulAllowedMechanismsLen)
+{
+       CK_RV rv;
+
+       CK_KEY_TYPE obj_type = CKK_VENDOR_DEFINED;
+       CK_DATE obj_start;
+       CK_DATE obj_end;
+       CK_BBOOL obj_derive = CK_FALSE;
+       CK_BBOOL obj_local = CK_FALSE;
+       CK_MECHANISM_TYPE obj_mech = CKM_VENDOR_DEFINED;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_ID, NULL_PTR, 0 },
+               { CKA_KEY_TYPE, &obj_type, sizeof(obj_type) },
+               { CKA_START_DATE, &obj_start, sizeof(obj_start) },
+               { CKA_END_DATE, &obj_end, sizeof(obj_end) },
+               { CKA_DERIVE, &obj_derive, sizeof(obj_derive) },
+               { CKA_LOCAL, &obj_local, sizeof(obj_local) },
+               { CKA_KEY_GEN_MECHANISM, &obj_mech, sizeof(obj_mech) },
+               { CKA_ALLOWED_MECHANISMS, NULL_PTR, 0 }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 8) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulIdLen);
+       CPPUNIT_ASSERT(obj_type == keyType);
+       CPPUNIT_ASSERT(attribs[2].ulValueLen == ulStartDateLen);
+       CPPUNIT_ASSERT(attribs[3].ulValueLen == ulEndDateLen);
+       CPPUNIT_ASSERT(obj_derive == bDerive);
+       CPPUNIT_ASSERT(obj_local == bLocal);
+       CPPUNIT_ASSERT(obj_mech == keyMechanismType);
+       CPPUNIT_ASSERT(attribs[7].ulValueLen == ulAllowedMechanismsLen);
+
+       if (ulIdLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pId, ulIdLen) == 0);
+       if (ulStartDateLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[2].pValue, &startDate, ulStartDateLen) == 0);
+       if (ulEndDateLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[3].pValue, &endDate, ulEndDateLen) == 0);
+       if (ulAllowedMechanismsLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[7].pValue, pAllowedMechanisms, ulAllowedMechanismsLen) == 0);
+
+       free(attribs[0].pValue);
+}
+
+void ObjectTests::checkCommonPublicKeyAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen, CK_BBOOL /*bEncrypt*/, CK_BBOOL /*bVerify*/, CK_BBOOL /*bVerifyRecover*/, CK_BBOOL /*bWrap*/, CK_BBOOL bTrusted, CK_ATTRIBUTE_PTR pWrapTemplate, CK_ULONG ulWrapTemplateLen)
+{
+       CK_RV rv;
+
+       CK_BBOOL obj_encrypt = CK_FALSE;
+       CK_BBOOL obj_verify = CK_FALSE;
+       CK_BBOOL obj_verify_recover = CK_FALSE;
+       CK_BBOOL obj_wrap = CK_FALSE;
+       CK_BBOOL obj_trusted = CK_FALSE;
+       CK_LONG len_wrap_template = ulWrapTemplateLen;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_SUBJECT, NULL_PTR, 0 },
+               { CKA_ENCRYPT, &obj_encrypt, sizeof(obj_encrypt) },
+               { CKA_VERIFY, &obj_verify, sizeof(obj_verify) },
+               { CKA_VERIFY_RECOVER, &obj_verify_recover, sizeof(obj_verify_recover) },
+               { CKA_WRAP, &obj_wrap, sizeof(obj_wrap) },
+               { CKA_TRUSTED, &obj_trusted, sizeof(obj_trusted) },
+               { CKA_WRAP_TEMPLATE, pWrapTemplate, ulWrapTemplateLen }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 7) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulSubjectLen);
+       /* Default is token-specifict
+       CPPUNIT_ASSERT(obj_encrypt == bEncrypt);
+       CPPUNIT_ASSERT(obj_verify == bVerify);
+       CPPUNIT_ASSERT(obj_verify_recover == bVerifyRecover);
+       CPPUNIT_ASSERT(obj_wrap == bWrap); */
+       CPPUNIT_ASSERT(obj_trusted == bTrusted);
+       len_wrap_template = attribs[6].ulValueLen;
+       CPPUNIT_ASSERT(len_wrap_template == 0);
+       if (ulSubjectLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pSubject, ulSubjectLen) == 0);
+
+       free(attribs[0].pValue);
+}
+
+void ObjectTests::checkCommonPrivateKeyAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen, CK_BBOOL bSensitive, CK_BBOOL bDecrypt, CK_BBOOL bSign, CK_BBOOL bSignRecover, CK_BBOOL bUnwrap, CK_BBOOL bExtractable, CK_BBOOL bAlwaysSensitive, CK_BBOOL bNeverExtractable, CK_BBOOL bWrapWithTrusted, CK_ATTRIBUTE_PTR pUnwrapTemplate, CK_ULONG ulUnwrapTemplateLen, CK_BBOOL bAlwaysAuthenticate)
+{
+       CK_RV rv;
+
+       CK_BBOOL obj_sensitive = CK_FALSE;
+       CK_BBOOL obj_decrypt = CK_FALSE;
+       CK_BBOOL obj_sign = CK_FALSE;
+       CK_BBOOL obj_sign_recover = CK_FALSE;
+       CK_BBOOL obj_unwrap = CK_FALSE;
+       CK_BBOOL obj_extractable = CK_FALSE;
+       CK_BBOOL obj_always_sensitive = CK_FALSE;
+       CK_BBOOL obj_never_extractable = CK_FALSE;
+       CK_BBOOL obj_wrap_with_trusted = CK_FALSE;
+       CK_BBOOL obj_always_authenticate = CK_FALSE;
+       CK_LONG len_unwrap_template = ulUnwrapTemplateLen;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_SUBJECT, NULL_PTR, 0 },
+               { CKA_SENSITIVE, &obj_sensitive, sizeof(obj_sensitive) },
+               { CKA_DECRYPT, &obj_decrypt, sizeof(obj_decrypt) },
+               { CKA_SIGN, &obj_sign, sizeof(obj_sign) },
+               { CKA_SIGN_RECOVER, &obj_sign_recover, sizeof(obj_sign_recover) },
+               { CKA_UNWRAP, &obj_unwrap, sizeof(obj_unwrap) },
+               { CKA_EXTRACTABLE, &obj_extractable, sizeof(obj_extractable) },
+               { CKA_ALWAYS_SENSITIVE, &obj_always_sensitive, sizeof(obj_always_sensitive) },
+               { CKA_NEVER_EXTRACTABLE, &obj_never_extractable, sizeof(obj_never_extractable) },
+               { CKA_WRAP_WITH_TRUSTED, &obj_wrap_with_trusted, sizeof(obj_wrap_with_trusted) },
+               { CKA_UNWRAP_TEMPLATE, pUnwrapTemplate, ulUnwrapTemplateLen },
+               { CKA_ALWAYS_AUTHENTICATE, &obj_always_authenticate, sizeof(obj_always_authenticate) }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 12) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulSubjectLen);
+       CPPUNIT_ASSERT(obj_sensitive == bSensitive);
+       CPPUNIT_ASSERT(obj_decrypt == bDecrypt);
+       CPPUNIT_ASSERT(obj_sign == bSign);
+       CPPUNIT_ASSERT(obj_sign_recover == bSignRecover);
+       CPPUNIT_ASSERT(obj_unwrap == bUnwrap);
+       CPPUNIT_ASSERT(obj_extractable == bExtractable);
+       CPPUNIT_ASSERT(obj_always_sensitive == bAlwaysSensitive);
+       CPPUNIT_ASSERT(obj_never_extractable == bNeverExtractable);
+       CPPUNIT_ASSERT(obj_wrap_with_trusted == bWrapWithTrusted);
+       CPPUNIT_ASSERT(obj_always_authenticate == bAlwaysAuthenticate);
+       len_unwrap_template = attribs[10].ulValueLen;
+       CPPUNIT_ASSERT(len_unwrap_template == 0);
+       if (ulSubjectLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pSubject, ulSubjectLen) == 0);
+
+       free(attribs[0].pValue);
+}
+
+void ObjectTests::checkCommonRSAPublicKeyAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BYTE_PTR pModulus, CK_ULONG ulModulusLen, CK_ULONG ulModulusBits, CK_BYTE_PTR pPublicExponent, CK_ULONG ulPublicExponentLen)
+{
+       CK_RV rv;
+
+       CK_ULONG obj_bits = 0;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_MODULUS, NULL_PTR, 0 },
+               { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 },
+               { CKA_MODULUS_BITS, &obj_bits, sizeof(obj_bits) }
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+       attribs[1].pValue = (CK_VOID_PTR)malloc(attribs[1].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 3) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulModulusLen);
+       CPPUNIT_ASSERT(attribs[1].ulValueLen == ulPublicExponentLen);
+       CPPUNIT_ASSERT(obj_bits == ulModulusBits);
+       if (ulModulusLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pModulus, ulModulusLen) == 0);
+       if (ulPublicExponentLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[1].pValue, pPublicExponent, ulPublicExponentLen) == 0);
+
+       free(attribs[0].pValue);
+       free(attribs[1].pValue);
+}
+
+void ObjectTests::checkCommonRSAPrivateKeyAttributes(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_BYTE_PTR pModulus, CK_ULONG ulModulusLen, CK_BYTE_PTR /*pPublicExponent*/, CK_ULONG /*ulPublicExponentLen*/, CK_BYTE_PTR pPrivateExponent, CK_ULONG ulPrivateExponentLen, CK_BYTE_PTR /*pPrime1*/, CK_ULONG /*ulPrime1Len*/, CK_BYTE_PTR /*pPrime2*/, CK_ULONG /*ulPrime2Len*/, CK_BYTE_PTR /*pExponent1*/, CK_ULONG /*ulExponent1Len*/, CK_BYTE_PTR /*pExponent2*/, CK_ULONG /*ulExponent2Len*/, CK_BYTE_PTR /*pCoefficient*/, CK_ULONG /*ulCoefficientLen*/)
+{
+       CK_RV rv;
+
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_MODULUS, NULL_PTR, 0 },
+               { CKA_PRIVATE_EXPONENT, NULL_PTR, 0 }
+               /* Some tokens may only store modulus and private exponent
+               { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 },
+               { CKA_PRIME_1, NULL_PTR, 0 },
+               { CKA_PRIME_2, NULL_PTR, 0 },
+               { CKA_EXPONENT_1, NULL_PTR, 0 },
+               { CKA_EXPONENT_2, NULL_PTR, 0 },
+               { CKA_COEFFICIENT, NULL_PTR, 0 }, */
+       };
+
+       // Get length
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       attribs[0].pValue = (CK_VOID_PTR)malloc(attribs[0].ulValueLen);
+       attribs[1].pValue = (CK_VOID_PTR)malloc(attribs[1].ulValueLen);
+
+       // Check values
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &attribs[0], 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == ulModulusLen);
+       CPPUNIT_ASSERT(attribs[1].ulValueLen == ulPrivateExponentLen);
+       if (ulModulusLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[0].pValue, pModulus, ulModulusLen) == 0);
+       if (ulPrivateExponentLen > 0)
+               CPPUNIT_ASSERT(memcmp(attribs[1].pValue, pPrivateExponent, ulPrivateExponentLen) == 0);
+
+       free(attribs[0].pValue);
+       free(attribs[1].pValue);
+}
+
+CK_RV ObjectTests::createDataObjectMinimal(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject)
+{
+       CK_OBJECT_CLASS cClass = CKO_DATA;
+       CK_UTF8CHAR label[] = "A data object";
+       CK_ATTRIBUTE objTemplate[] = {
+               // Common
+               { CKA_CLASS, &cClass, sizeof(cClass) },
+
+               // Storage
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               //CKA_MODIFIABLE
+               { CKA_LABEL, label, sizeof(label)-1 },
+               //CKA_COPYABLE
+               //CKA_DESTROYABLE
+
+               // Data
+        };
+
+       hObject = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE),&hObject) );
+}
+
+CK_RV ObjectTests::createDataObjectMCD(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_BBOOL bModifiable, CK_BBOOL bCopyable, CK_BBOOL bDestroyable, CK_OBJECT_HANDLE &hObject)
+{
+       CK_OBJECT_CLASS cClass = CKO_DATA;
+       CK_UTF8CHAR label[] = "A data object";
+       CK_ATTRIBUTE objTemplate[] = {
+               // Common
+               { CKA_CLASS, &cClass, sizeof(cClass) },
+
+               // Storage
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_MODIFIABLE, &bModifiable, sizeof(bModifiable) },
+               { CKA_LABEL, label, sizeof(label)-1 },
+               { CKA_COPYABLE, &bCopyable, sizeof(bCopyable) },
+               { CKA_DESTROYABLE, &bDestroyable, sizeof(bDestroyable) }
+
+               // Data
+        };
+
+       hObject = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE),&hObject) );
+}
+
+CK_RV ObjectTests::createDataObjectNormal(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject)
+{
+       CK_OBJECT_CLASS cClass = CKO_DATA;
+       CK_UTF8CHAR label[] = "A data object";
+
+       CK_UTF8CHAR application[] = "An application";
+       CK_BYTE objectID[] = "invalid object id";
+       CK_BYTE data[] = "Sample data";
+
+       CK_ATTRIBUTE objTemplate[] = {
+               // Common
+               { CKA_CLASS, &cClass, sizeof(cClass) },
+
+               // Storage
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               //CKA_MODIFIABLE
+               { CKA_LABEL, label, sizeof(label)-1 },
+               //CKA_COPYABLE
+               //CKA_DESTROYABLE
+
+               // Data
+               { CKA_APPLICATION, application, sizeof(application)-1 },
+               { CKA_OBJECT_ID, objectID, sizeof(objectID) },
+               { CKA_VALUE, data, sizeof(data) }
+       };
+
+       hObject = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE),&hObject) );
+}
+
+CK_RV ObjectTests::createCertificateObjectIncomplete(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject)
+{
+       CK_OBJECT_CLASS cClass = CKO_CERTIFICATE;
+       CK_ATTRIBUTE objTemplate[] = {
+               // Common
+               { CKA_CLASS, &cClass, sizeof(cClass) },
+               // Storage
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) }
+       };
+
+       hObject = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE),&hObject) );
+}
+
+CK_RV ObjectTests::createCertificateObjectX509(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject)
+{
+       CK_OBJECT_CLASS cClass = CKO_CERTIFICATE;
+       CK_CERTIFICATE_TYPE cType = CKC_X_509;
+       const char *pSubject = "invalid subject der";
+       const char *pValue = "invalid certificate der";
+
+       CK_ATTRIBUTE objTemplate[] = {
+               // Common
+               { CKA_CLASS, &cClass, sizeof(cClass) },
+               // Storage
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               // Common Certificate Object Attributes
+               { CKA_CERTIFICATE_TYPE, &cType, sizeof(cType) },
+               // X.509 Certificate Object Attributes
+               { CKA_SUBJECT, (CK_VOID_PTR)pSubject, strlen(pSubject) },
+               { CKA_VALUE, (CK_VOID_PTR)pValue, strlen(pValue) }
+       };
+
+       hObject = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE),&hObject) );
+}
+
+CK_RV ObjectTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BYTE pubExp[] = {0x01, 0x00, 0x01};
+       CK_BYTE subject[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bFalse, sizeof(bFalse) },
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) },
+               { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_SUBJECT, &subject[0], sizeof(subject) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_UNWRAP, &bFalse, sizeof(bFalse) }
+       };
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                                                        pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        &hPuk, &hPrk) );
+}
+
+void ObjectTests::testCreateObject()
+{
+//    printf("\ntestCreateObject\n");
+
+       // [PKCS#11 v2.40, C_CreateObject]
+       // a. Only session objects can be created during read-only session.
+       // b. Only public objects can be created unless the normal user is logged in.
+       // c. Key object will have CKA_LOCAL == CK_FALSE.
+       // d. If key object is secret or a private key then both CKA_ALWAYS_SENSITIVE == CK_FALSE and CKA_NEVER_EXTRACTABLE == CKA_FALSE.
+
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject;
+
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE genKeyType = CKK_GENERIC_SECRET;
+       CK_BYTE keyPtr[128];
+       CK_ULONG keyLen = 128;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) },
+               { CKA_CLASS, &secretClass, sizeof(secretClass) },
+               { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE, keyPtr, keyLen }
+       };
+
+       CK_BBOOL local;
+       CK_BBOOL always;
+       CK_BBOOL never;
+       CK_ATTRIBUTE getTemplate[] = {
+               { CKA_LOCAL, &local, sizeof(local) },
+               { CKA_ALWAYS_SENSITIVE, &always, sizeof(always) },
+               { CKA_NEVER_EXTRACTABLE, &never, sizeof(never) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       /////////////////////////////////
+       // READ-ONLY & PUBLIC
+       /////////////////////////////////
+
+       // Open read-only session and don't login
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be allowed to create public session objects
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Only public objects can be created unless the normal user is logged in
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       // We should not be allowed to create token objects because the session is read-only
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       /////////////////////////////////
+       // READ-ONLY & USER
+       /////////////////////////////////
+
+       // Login USER into the read-only session
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // We should be allowed to create public session objects
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be allowed to create private session objects
+       rv  = createDataObjectMinimal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should not be allowed to create token objects.
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       /////////////////////////////////
+       // READ-WRITE & PUBLIC
+       /////////////////////////////////
+
+       // Open as read-write session but don't login.
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be allowed to create public session objects
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv ==  CKR_USER_NOT_LOGGED_IN);
+
+       // We should be allowed to create public token objects even when not logged in.
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv ==  CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should not be able to create private token objects because we are not logged in now
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       /////////////////////////////////
+       // READ-WRITE & USER
+       /////////////////////////////////
+
+       // Open as read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login to the read-write session
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // We should always be allowed to create public session objects
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be able allowed to create private session objects because we are logged in.
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be allowed to create public token objects even when not logged in.
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should be able to create private token objects because we are logged in now
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       /////////////////////////////////
+       // READ-WRITE & SO
+       /////////////////////////////////
+
+       // Open as read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login to the read-write session
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_SO,m_soPin1,m_soPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // We should always be allowed to create public session objects
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Only public objects can be created unless the normal user is logged in.
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       // We should be allowed to create public token objects even when not logged in.
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Only public objects can be created unless the normal user is logged in.
+       rv = createDataObjectMinimal(hSession, ON_TOKEN, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       /////////////////////////////////
+       // READ-WRITE & USER
+       /////////////////////////////////
+
+       // Open as read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login to the read-write session
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Create a secret object
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, keyPtr, keyLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, getTemplate, 3) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(local == CK_FALSE);
+       CPPUNIT_ASSERT(always == CK_FALSE);
+       CPPUNIT_ASSERT(never == CK_FALSE);
+
+       // Destroy the secret object
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testCopyObject()
+{
+//    printf("\ntestCopyObject\n");
+
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject;
+       CK_OBJECT_HANDLE hObjectCopy;
+       CK_OBJECT_HANDLE hObject1;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session and don't login
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get a public session object
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMCD(hSession, IN_SESSION, IS_PUBLIC, CK_TRUE, CK_FALSE, CK_TRUE, hObjectCopy);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Allowed to copy it
+       const char *pLabel = "Label modified via C_CopyObject";
+       CK_BBOOL bToken = CK_FALSE;
+       CK_BBOOL bPrivate = CK_FALSE;
+       CK_OBJECT_CLASS cClass = CKO_DATA;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_LABEL, (CK_UTF8CHAR_PTR)pLabel, strlen(pLabel) },
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_CLASS, &cClass, sizeof(cClass) }
+       };
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 1, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Not allowed to copy.
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObjectCopy, &attribs[0], 1, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_ACTION_PROHIBITED);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObjectCopy) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Still allowed when still session and public
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Not allowed to overwrite an !ck8 attribute
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 4, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_READ_ONLY);
+
+       // Not allowed to go on token
+       bToken = CK_TRUE;
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       bToken = CK_FALSE;
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       // Not allowed to go to private
+       bPrivate = CK_TRUE;
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       bPrivate = CK_FALSE;
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create a read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private object
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get a public session object
+       rv = createDataObjectNormal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Allowed to go on token
+       bToken = CK_TRUE;
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Allowed to go to private
+       bPrivate = CK_TRUE;
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Not allowed to change a !ck8 parameter
+       CK_BYTE id[] = "Another object ID";
+       attribs[3].type = CKA_OBJECT_ID;
+       attribs[3].pValue = id;
+       attribs[3].ulValueLen = sizeof(id);
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 4, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_READ_ONLY);
+
+       // Not allowed to downgrade privacy
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectNormal(hSession, IN_SESSION, IS_PRIVATE, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       bToken = CK_FALSE;
+       bPrivate = CK_FALSE;
+       rv = CRYPTOKI_F_PTR( C_CopyObject(hSession, hObject, &attribs[0], 3, &hObject1) );
+       CPPUNIT_ASSERT(rv == CKR_TEMPLATE_INCONSISTENT);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testDestroyObject()
+{
+//    printf("\ntestDestroyObject\n");
+
+       // [PKCS#11 v2.40, C_Logout] When logout is successful...
+       // a. Any of the application's handles to private objects become invalid.
+       // b. Even if a user is later logged back into the token those handles remain invalid.
+       // c. All private session objects from sessions belonging to the application area destroyed.
+
+       // [PKCS#11 v2.40, C_CreateObject]
+       // Only session objects can be created during read-only session.
+       // Only public objects can be created unless the normal user is logged in.
+
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+       CK_OBJECT_HANDLE hObjectSessionPublic;
+       CK_OBJECT_HANDLE hObjectSessionPrivate;
+       CK_OBJECT_HANDLE hObjectTokenPublic;
+       CK_OBJECT_HANDLE hObjectTokenPrivate;
+       CK_OBJECT_HANDLE hObjectDestroy;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Try to destroy an invalid object using an invalid session
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       // Create a read-only session.
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Trying to destroy an invalid object in a read-only session
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_OBJECT_HANDLE_INVALID);
+
+       // Create a read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Trying to destroy an invalid object in a read-write session
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_OBJECT_HANDLE_INVALID);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Create all permutations of session/token, public/private objects
+       rv = createDataObjectMinimal(hSessionRW, IN_SESSION, IS_PUBLIC, hObjectSessionPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, IN_SESSION, IS_PRIVATE, hObjectSessionPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PUBLIC, hObjectTokenPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PRIVATE, hObjectTokenPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMCD(hSessionRW, IN_SESSION, IS_PUBLIC, CK_TRUE, CK_TRUE, CK_FALSE, hObjectDestroy);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // We should not be able to destroy a non-destroyable object.
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,hObjectDestroy) );
+       CPPUNIT_ASSERT(rv == CKR_ACTION_PROHIBITED);
+
+       // On a read-only session we should not be able to destroy the public token object
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,hObjectTokenPublic) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       // On a read-only session we should not be able to destroy the private token object
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,hObjectTokenPrivate) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       // Logout with a different session than the one used for login should be fine.
+       rv = CRYPTOKI_F_PTR( C_Logout(hSessionRW) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Login USER into the sessions so we can destroy private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // We should be able to destroy the public session object from a read-only session.
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRO,hObjectSessionPublic) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // All private session objects should have been destroyed when logging out.
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRW,hObjectSessionPrivate) );
+       CPPUNIT_ASSERT(rv == CKR_OBJECT_HANDLE_INVALID);
+
+       // We should be able to destroy the public token object now.
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRW,hObjectTokenPublic) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // All handles to private token objects should have been invalidated when logging out.
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSessionRW,hObjectTokenPrivate) );
+       CPPUNIT_ASSERT(rv == CKR_OBJECT_HANDLE_INVALID);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testGetObjectSize()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open a session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get an object
+       rv = createDataObjectMinimal(hSession, IN_SESSION, IS_PUBLIC, hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get the object size
+       CK_ULONG objectSize;
+       rv = CRYPTOKI_F_PTR( C_GetObjectSize(hSession, hObject, &objectSize) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(objectSize == CK_UNAVAILABLE_INFORMATION);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testGetAttributeValue()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+       CK_OBJECT_HANDLE hObjectSessionPublic;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Try to destroy an invalid object using an invalid session
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRO,CK_INVALID_HANDLE,NULL,1) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       // Create all permutations of session/token, public/private objects
+       rv = createDataObjectMinimal(hSessionRO, IN_SESSION, IS_PUBLIC, hObjectSessionPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_OBJECT_CLASS cClass = CKO_VENDOR_DEFINED;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_CLASS, &cClass, sizeof(cClass) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue (hSessionRO,hObjectSessionPublic,&attribs[0],1) );//sizeof(attribs)/sizeof(CK_ATTRIBUTE));
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testSetAttributeValue()
+{
+       // [PKCS#11 v2.40, 4.1.1 Creating objects]
+       //    1. If the supplied template specifies a value for an invalid attribute, then the attempt
+       //    should fail with the error code CKR_ATTRIBUTE_TYPE_INVALID. An attribute
+       //    is valid if it is either one of the attributes described in the Cryptoki specification or an
+       //    additional vendor-specific attribute supported by the library and token.
+       //
+       //    2. If the supplied template specifies an invalid value for a valid attribute, then the
+       //    attempt should fail with the error code CKR_ATTRIBUTE_VALUE_INVALID.
+       //    The valid values for Cryptoki attributes are described in the Cryptoki specification.
+       //
+       //    3. If the supplied template specifies a value for a read-only attribute, then the attempt
+       //    should fail with the error code CKR_ATTRIBUTE_READ_ONLY. Whether or not a
+       //    given Cryptoki attribute is read-only is explicitly stated in the Cryptoki specification;
+       //    however, a particular library and token may be even more restrictive than Cryptoki
+       //    specifies. In other words, an attribute which Cryptoki says is not read-only may
+       //    nonetheless be read-only under certain circumstances (i.e., in conjunction with some
+       //    combinations of other attributes) for a particular library and token. Whether or not a
+       //    given non-Cryptoki attribute is read-only is obviously outside the scope of Cryptoki.
+       //
+       //    4. N/A (Does not apply to C_SetAttributeValue)
+       //
+       //    5. If the attribute values in the supplied template, together with any default attribute
+       //    values and any attribute values contributed to the object by the object-creation
+       //    function itself, are inconsistent, then the attempt should fail with the error code
+       //    CKR_TEMPLATE_INCONSISTENT. A set of attribute values is inconsistent if not
+       //    all of its members can be satisfied simultaneously by the token, although each value
+       //    individually is valid in Cryptoki. One example of an inconsistent template would be
+       //    using a template which specifies two different values for the same attribute. Another
+       //    example would be trying to create a secret key object with an attribute which is
+       //    appropriate for various types of public keys or private keys, but not for secret keys.
+       //    A final example would be a template with an attribute that violates some token
+       //    specific requirement. Note that this final example of an inconsistent template is
+       //    token-dependent—on a different token, such a template might not be inconsistent.
+       //
+       //    6. If the supplied template specifies the same value for a particular attribute more than
+       //    once (or the template specifies the same value for a particular attribute that the object-
+       //    creation function itself contributes to the object), then the behavior of Cryptoki is not
+       //    completely specified. The attempt to create an object can either succeed—thereby
+       //    creating the same object that would have been created if the multiply-specified
+       //    attribute had only appeared once—or it can fail with error code
+       //    CKR_TEMPLATE_INCONSISTENT. Library developers are encouraged to make
+       //    their libraries behave as though the attribute had only appeared once in the template;
+       //    application developers are strongly encouraged never to put a particular attribute into
+       //    a particular template more than once.
+
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+       CK_OBJECT_HANDLE hObjectSessionPublic;
+       CK_OBJECT_HANDLE hObjectSessionPrivate;
+       CK_OBJECT_HANDLE hObjectTokenPublic;
+       CK_OBJECT_HANDLE hObjectTokenPrivate;
+       CK_OBJECT_HANDLE hObjectSet;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Create all permutations of session/token, public/private objects
+       rv = createDataObjectMinimal(hSessionRO, IN_SESSION, IS_PUBLIC, hObjectSessionPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, IN_SESSION, IS_PRIVATE, hObjectSessionPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PUBLIC, hObjectTokenPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PRIVATE, hObjectTokenPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMCD(hSessionRO, IN_SESSION, IS_PUBLIC, CK_FALSE, CK_TRUE, CK_TRUE, hObjectSet);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check that label can be modified on all combintations of session/token and public/private objects
+       const char  *pLabel = "Label modified via C_SetAttributeValue";
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_LABEL, (CK_UTF8CHAR_PTR)pLabel, strlen(pLabel) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectSessionPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectSessionPrivate,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectTokenPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRW,hObjectTokenPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectTokenPrivate,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRW,hObjectTokenPrivate,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectSet,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_ACTION_PROHIBITED);
+
+       attribs[0].pValue = NULL_PTR;
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRO,hObjectSessionPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == strlen(pLabel));
+
+       char pStoredLabel[64];
+       attribs[0].pValue = &pStoredLabel[0];
+       attribs[0].ulValueLen = 64;
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRO,hObjectSessionPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribs[0].ulValueLen == strlen(pLabel));
+       CPPUNIT_ASSERT(memcmp(pLabel,pStoredLabel,strlen(pLabel)) == 0);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Close session
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testFindObjects()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+       CK_OBJECT_HANDLE hObjectSessionPublic;
+       CK_OBJECT_HANDLE hObjectSessionPrivate;
+       CK_OBJECT_HANDLE hObjectTokenPublic;
+       CK_OBJECT_HANDLE hObjectTokenPrivate;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Create all permutations of session/token, public/private objects
+       rv = createDataObjectMinimal(hSessionRO, IN_SESSION, IS_PUBLIC, hObjectSessionPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, IN_SESSION, IS_PRIVATE, hObjectSessionPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PUBLIC, hObjectTokenPublic);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = createDataObjectMinimal(hSessionRW, ON_TOKEN, IS_PRIVATE, hObjectTokenPrivate);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Set labels for the objects
+       const char  *pLabel = "Label modified via C_SetAttributeValue";
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_LABEL, (CK_UTF8CHAR_PTR)pLabel, strlen(pLabel) }
+       };
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectSessionPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRO,hObjectSessionPrivate,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRW,hObjectTokenPublic,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue (hSessionRW,hObjectTokenPrivate,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Now find the objects while logged in should find them all.
+       rv = CRYPTOKI_F_PTR( C_FindObjectsInit(hSessionRO,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_OBJECT_HANDLE hObjects[16];
+       CK_ULONG ulObjectCount = 0;
+       rv = CRYPTOKI_F_PTR( C_FindObjects(hSessionRO,&hObjects[0],16,&ulObjectCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(4 == ulObjectCount);
+       rv = CRYPTOKI_F_PTR( C_FindObjectsFinal(hSessionRO) );
+
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Now find the objects while no longer logged in should find only 2
+       rv = CRYPTOKI_F_PTR( C_FindObjectsInit(hSessionRO,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_FindObjects(hSessionRO,&hObjects[0],16,&ulObjectCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(2 == ulObjectCount);
+       rv = CRYPTOKI_F_PTR( C_FindObjectsFinal(hSessionRO) );
+
+       // Close the session used to create the session objects, should also destroy the session objects.
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Now find just the public token object as public session object should be gone now.
+       rv = CRYPTOKI_F_PTR( C_FindObjectsInit(hSessionRW,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_FindObjects(hSessionRW,&hObjects[0],16,&ulObjectCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(1 == ulObjectCount);
+       rv = CRYPTOKI_F_PTR( C_FindObjectsFinal(hSessionRW) );
+
+       // Login USER into the sessions so we can gain access to private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRW,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Now find just the public token object as public session object should be gone now.
+       rv = CRYPTOKI_F_PTR( C_FindObjectsInit(hSessionRW,&attribs[0],1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_FindObjects(hSessionRW,&hObjects[0],16,&ulObjectCount) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(2 == ulObjectCount);
+       rv = CRYPTOKI_F_PTR( C_FindObjectsFinal(hSessionRW) );
+}
+
+
+void ObjectTests::testGenerateKeys()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token public/private key pairs.
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = generateRsaKeyPair(hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testCreateCertificates()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       rv = createCertificateObjectIncomplete(hSession,IN_SESSION,IS_PUBLIC,hObject);
+       CPPUNIT_ASSERT(rv == CKR_TEMPLATE_INCOMPLETE);
+       rv = createCertificateObjectX509(hSession,IN_SESSION,IS_PUBLIC,hObject);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_BYTE pCheckValue[] = { 0x2b, 0x84, 0xf6 };
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_CHECK_VALUE, pCheckValue, sizeof(pCheckValue) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue(hSession, hObject, attribs, 1) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_READ_ONLY);
+}
+
+void ObjectTests::testDefaultDataAttributes()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       // Minimal data object
+       CK_OBJECT_CLASS objClass = CKO_DATA;
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal data object
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check attributes in data object
+       checkCommonObjectAttributes(hSession, hObject, objClass);
+       checkCommonStorageObjectAttributes(hSession, hObject, CK_FALSE, CK_TRUE, CK_TRUE, NULL_PTR, 0, CK_TRUE, CK_TRUE);
+       checkDataObjectAttributes(hSession, hObject, NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0);
+}
+
+void ObjectTests::testDefaultX509CertAttributes()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       // Minimal X509 certificate object
+       CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+       CK_CERTIFICATE_TYPE certificateType = CKC_X_509;
+       CK_BYTE pSubject[] = "Test1";
+       CK_BYTE pValue[] = "Test2";
+       CK_BYTE pCheckValue[] = { 0x2b, 0x84, 0xf6 };
+       CK_DATE emptyDate;
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_CERTIFICATE_TYPE, &certificateType, sizeof(certificateType) },
+               { CKA_SUBJECT, pSubject, sizeof(pSubject)-1 },
+               { CKA_VALUE, pValue, sizeof(pValue)-1 }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal X509 certificate
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check attributes in X509 certificate object
+       checkCommonObjectAttributes(hSession, hObject, objClass);
+       checkCommonStorageObjectAttributes(hSession, hObject, CK_FALSE, CK_FALSE, CK_TRUE, NULL_PTR, 0, CK_TRUE, CK_TRUE);
+       memset(&emptyDate, 0, sizeof(emptyDate));
+       checkCommonCertificateObjectAttributes(hSession, hObject, CKC_X_509, CK_FALSE, 0, pCheckValue, sizeof(pCheckValue), emptyDate, 0, emptyDate, 0);
+       checkX509CertificateObjectAttributes(hSession, hObject, pSubject, sizeof(pSubject)-1, NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0, pValue, sizeof(pValue)-1, NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0, 0, CKM_SHA_1);
+}
+
+void ObjectTests::testDefaultRSAPubAttributes()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       // Minimal RSA public key object
+       CK_OBJECT_CLASS objClass = CKO_PUBLIC_KEY;
+       CK_KEY_TYPE objType = CKK_RSA;
+       CK_BYTE pN[] = { 0xC6, 0x47, 0xDD, 0x74, 0x3B, 0xCB, 0xDC, 0x6F, 0xCE, 0xA7,
+                        0xF0, 0x5F, 0x29, 0x4B, 0x27, 0x00, 0xCC, 0x92, 0xE9, 0x20,
+                        0x8A, 0x2C, 0x87, 0x36, 0x47, 0x24, 0xB0, 0xD5, 0x7D, 0xB0,
+                        0x92, 0x01, 0xA0, 0xA3, 0x55, 0x2E, 0x3F, 0xFE, 0xA7, 0x4C,
+                        0x4B, 0x3F, 0x9D, 0x4E, 0xCB, 0x78, 0x12, 0xA9, 0x42, 0xAD,
+                        0x51, 0x1F, 0x3B, 0xBD, 0x3D, 0x6A, 0xE5, 0x38, 0xB7, 0x45,
+                        0x65, 0x50, 0x30, 0x35 };
+        CK_BYTE pE[] = { 0x01, 0x00, 0x01 };
+       CK_DATE emptyDate;
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_KEY_TYPE, &objType, sizeof(objType) },
+               { CKA_MODULUS, pN, sizeof(pN) },
+               { CKA_PUBLIC_EXPONENT, pE, sizeof(pE) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal RSA public key object
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check attributes in RSA public key object
+       checkCommonObjectAttributes(hSession, hObject, objClass);
+       checkCommonStorageObjectAttributes(hSession, hObject, CK_FALSE, CK_FALSE, CK_TRUE, NULL_PTR, 0, CK_TRUE, CK_TRUE);
+       memset(&emptyDate, 0, sizeof(emptyDate));
+       checkCommonKeyAttributes(hSession, hObject, objType, NULL_PTR, 0, emptyDate, 0, emptyDate, 0, CK_FALSE, CK_FALSE, CK_UNAVAILABLE_INFORMATION, NULL_PTR, 0);
+       checkCommonPublicKeyAttributes(hSession, hObject, NULL_PTR, 0, CK_TRUE, CK_TRUE, CK_TRUE, CK_TRUE, CK_FALSE, NULL_PTR, 0);
+       checkCommonRSAPublicKeyAttributes(hSession, hObject, pN, sizeof(pN), 512, pE, sizeof(pE));
+}
+
+void ObjectTests::testDefaultRSAPrivAttributes()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       // Minimal RSA private key object
+       CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE objType = CKK_RSA;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BYTE pN[] = { 0xC6, 0x47, 0xDD, 0x74, 0x3B, 0xCB, 0xDC, 0x6F, 0xCE, 0xA7,
+                        0xF0, 0x5F, 0x29, 0x4B, 0x27, 0x00, 0xCC, 0x92, 0xE9, 0x20,
+                        0x8A, 0x2C, 0x87, 0x36, 0x47, 0x24, 0xB0, 0xD5, 0x7D, 0xB0,
+                        0x92, 0x01, 0xA0, 0xA3, 0x55, 0x2E, 0x3F, 0xFE, 0xA7, 0x4C,
+                        0x4B, 0x3F, 0x9D, 0x4E, 0xCB, 0x78, 0x12, 0xA9, 0x42, 0xAD,
+                        0x51, 0x1F, 0x3B, 0xBD, 0x3D, 0x6A, 0xE5, 0x38, 0xB7, 0x45,
+                        0x65, 0x50, 0x30, 0x35 };
+        CK_BYTE pD[] = { 0x6D, 0x94, 0x6B, 0xEB, 0xFF, 0xDC, 0x03, 0x80, 0x7B, 0x0A,
+                        0x4F, 0x0A, 0x98, 0x6C, 0xA3, 0x2A, 0x8A, 0xE4, 0xAA, 0x18,
+                        0x44, 0xA4, 0xA5, 0x39, 0x37, 0x0A, 0x2C, 0xFC, 0x5F, 0xD1,
+                        0x44, 0x6E, 0xCE, 0x25, 0x9B, 0xE5, 0xD1, 0x51, 0xAF, 0xA8,
+                        0x30, 0xD1, 0x4D, 0x3C, 0x60, 0x33, 0xB5, 0xED, 0x4C, 0x39,
+                        0xDA, 0x68, 0x78, 0xF9, 0x6B, 0x4F, 0x47, 0x55, 0xB2, 0x02,
+                        0x00, 0x7E, 0x9C, 0x05 };
+       CK_DATE emptyDate;
+       // Make the key non-sensitive and extractable so that we can test it.
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_KEY_TYPE, &objType, sizeof(objType) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) },
+               { CKA_MODULUS, pN, sizeof(pN) },
+               { CKA_PRIVATE_EXPONENT, pD, sizeof(pD) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal RSA public key object
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check attributes in RSA public key object
+       checkCommonObjectAttributes(hSession, hObject, objClass);
+       checkCommonStorageObjectAttributes(hSession, hObject, CK_FALSE, CK_TRUE, CK_TRUE, NULL_PTR, 0, CK_TRUE, CK_TRUE);
+       memset(&emptyDate, 0, sizeof(emptyDate));
+       checkCommonKeyAttributes(hSession, hObject, objType, NULL_PTR, 0, emptyDate, 0, emptyDate, 0, CK_FALSE, CK_FALSE, CK_UNAVAILABLE_INFORMATION, NULL_PTR, 0);
+       checkCommonPrivateKeyAttributes(hSession, hObject, NULL_PTR, 0, CK_FALSE, CK_TRUE, CK_TRUE, CK_TRUE, CK_TRUE, CK_TRUE, CK_FALSE, CK_FALSE, CK_FALSE, NULL_PTR, 0, CK_FALSE);
+       checkCommonRSAPrivateKeyAttributes(hSession, hObject, pN, sizeof(pN), NULL_PTR, 0, pD, sizeof(pD), NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0, NULL_PTR, 0);
+}
+
+void ObjectTests::testAlwaysNeverAttribute()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_BBOOL always;
+       CK_BBOOL never;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }
+       };
+       CK_ATTRIBUTE getTemplate[] = {
+               { CKA_ALWAYS_SENSITIVE, &always, sizeof(always) },
+               { CKA_NEVER_EXTRACTABLE, &never, sizeof(never) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create object
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism, pukAttribs, 1, prkAttribs, 2, &hPuk, &hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPrk, getTemplate, 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(always == CK_TRUE);
+       CPPUNIT_ASSERT(never == CK_TRUE);
+
+       // Set value
+       rv = CRYPTOKI_F_PTR( C_SetAttributeValue(hSession, hPrk, prkAttribs, 2) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_READ_ONLY);
+
+       // Create object
+       prkAttribs[0].pValue = &bFalse;
+       prkAttribs[1].pValue = &bTrue;
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism, pukAttribs, 1, prkAttribs, 2, &hPuk, &hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPrk, getTemplate, 2) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(always == CK_FALSE);
+       CPPUNIT_ASSERT(never == CK_FALSE);
+}
+
+void ObjectTests::testSensitiveAttributes()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BBOOL bSensitive = CK_TRUE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) }
+       };
+       // Sensitive attributes cannot be revealed in plaintext even if wrapping is allowed
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_SENSITIVE, &bSensitive, sizeof(bSensitive) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }
+       };
+       CK_ATTRIBUTE getTemplate[] = {
+               { CKA_PRIVATE_EXPONENT, NULL_PTR, 0 },
+               { CKA_PRIME_1, NULL_PTR, 0 },
+               { CKA_PRIME_2, NULL_PTR, 0 },
+               { CKA_EXPONENT_1, NULL_PTR, 0 },
+               { CKA_EXPONENT_2, NULL_PTR, 0 },
+               { CKA_COEFFICIENT, NULL_PTR, 0 }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create object
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism, pukAttribs, 1, prkAttribs, 2, &hPuk, &hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       for (int i = 0; i < 6; i++)
+       {
+               rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPrk, &getTemplate[i], 1) );
+               CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_SENSITIVE);
+       }
+
+       // Retry with non-sensitive object
+       bSensitive = CK_FALSE;
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism, pukAttribs, 1, prkAttribs, 2, &hPuk, &hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       for (int i = 0; i < 6; i++)
+       {
+               rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPrk, &getTemplate[i], 1) );
+               CPPUNIT_ASSERT(rv == CKR_OK);
+       }
+}
+
+void ObjectTests::testGetInvalidAttribute()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+
+       // Minimal data object
+       CK_OBJECT_CLASS objClass = CKO_DATA;
+       CK_BBOOL bSign;
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) }
+       };
+       CK_ATTRIBUTE getTemplate[] = {
+               { CKA_SIGN, &bSign, sizeof(bSign) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal data object
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, 1, &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Check value
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, getTemplate, 1) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+void ObjectTests::testReAuthentication()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1024;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_ALWAYS_AUTHENTICATE, &bTrue, sizeof(bTrue) }
+       };
+
+       CK_MECHANISM signMech = { CKM_SHA256_RSA_PKCS, NULL_PTR, 0 };
+       CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+       CK_BYTE signature256[256];
+       CK_ULONG signature256Len = sizeof(signature256);
+
+       CK_MECHANISM encMech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+       CK_BYTE cipherText[256];
+       CK_ULONG ulCipherTextLen = sizeof(cipherText);
+       CK_BYTE recoveredText[256];
+       CK_ULONG ulRecoveredTextLen = sizeof(recoveredText);
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create object
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism, pukAttribs, 1, prkAttribs, 4, &hPuk, &hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Test C_Sign with re-authentication with invalid and valid PIN
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length-1) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Test C_Sign without re-authentication
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       // Test C_SignUpdate with re-authentication
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SignUpdate(hSession, data, sizeof(data)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SignFinal(hSession, signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Test C_SignUpdate without re-authentication
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SignUpdate(hSession, data, sizeof(data)) );
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+       rv = CRYPTOKI_F_PTR( C_SignUpdate(hSession, data, sizeof(data)) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       // Test C_SignFinal with re-authentication
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SignFinal(hSession, signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Test C_SignFinal without re-authentication
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &signMech, hPrk) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_SignFinal(hSession, signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+       rv = CRYPTOKI_F_PTR( C_SignFinal(hSession, signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+
+       // Encrypt some data
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&encMech,hPuk) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,data,sizeof(data),cipherText,&ulCipherTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Test C_Decrypt with re-authentication
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&encMech,hPrk) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_CONTEXT_SPECIFIC,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       CPPUNIT_ASSERT(memcmp(data, &recoveredText[ulRecoveredTextLen-sizeof(data)], sizeof(data)) == 0);
+
+       // Test C_Decrypt without re-authentication
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&encMech,hPrk) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) );
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,cipherText,ulCipherTextLen,recoveredText,&ulRecoveredTextLen) );
+       CPPUNIT_ASSERT(rv == CKR_OPERATION_NOT_INITIALIZED);
+}
+
+void ObjectTests::testAllowedMechanisms()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+       CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
+       CK_BYTE key[65] = { "0000000000000000000000000000000000000000000000000000000000000000" };
+       CK_MECHANISM_TYPE allowedMechs[] = { CKM_SHA256_HMAC, CKM_SHA512_HMAC };
+       CK_ATTRIBUTE attribs[] = {
+                       { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+                       { CKA_CLASS, &secretClass, sizeof(secretClass) },
+                       { CKA_VALUE, &key, sizeof(key)-1 },
+                       { CKA_ALLOWED_MECHANISMS, &allowedMechs, sizeof(allowedMechs) }
+       };
+
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+
+       // SHA_1_HMAC is not an allowed mechanism
+       CK_MECHANISM mechanism = { CKM_SHA_1_HMAC, NULL_PTR, 0 };
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &mechanism, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_MECHANISM_INVALID);
+
+       // SHA256_HMAC is an allowed mechanism
+       mechanism.mechanism = CKM_SHA256_HMAC;
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &mechanism, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_BYTE signature256[256];
+       CK_ULONG signature256Len = sizeof(signature256);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature256, &signature256Len) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // SHA384_HMAC is not an allowed mechanism
+       mechanism.mechanism = CKM_SHA384_HMAC;
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &mechanism, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_MECHANISM_INVALID);
+
+       // SHA512_HMAC is an allowed mechanism
+       mechanism.mechanism = CKM_SHA512_HMAC;
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &mechanism, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CK_BYTE signature512[512];
+       CK_ULONG signature512Len = sizeof(signature512);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature512, &signature512Len) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void ObjectTests::testTemplateAttribute()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+       CK_BYTE pE[] = { 0x01, 0x00, 0x01 };
+       CK_MECHANISM_TYPE allowedMechs[] = { CKM_SHA256_HMAC, CKM_SHA512_HMAC };
+
+       // Wrap template
+       CK_KEY_TYPE wrapType = CKK_SHA256_HMAC;;
+       CK_ATTRIBUTE wrapTemplate[] = {
+               { CKA_KEY_TYPE, &wrapType, sizeof(wrapType) },
+               { CKA_PUBLIC_EXPONENT, pE, sizeof(pE) },
+               { CKA_ALLOWED_MECHANISMS, &allowedMechs, sizeof(allowedMechs) }
+       };
+
+       // Minimal public key object
+       CK_OBJECT_CLASS objClass = CKO_PUBLIC_KEY;
+       CK_KEY_TYPE objType = CKK_RSA;
+       CK_BYTE pN[] = { 0xC6, 0x47, 0xDD, 0x74, 0x3B, 0xCB, 0xDC, 0x6F, 0xCE, 0xA7,
+                        0xF0, 0x5F, 0x29, 0x4B, 0x27, 0x00, 0xCC, 0x92, 0xE9, 0x20,
+                        0x8A, 0x2C, 0x87, 0x36, 0x47, 0x24, 0xB0, 0xD5, 0x7D, 0xB0,
+                        0x92, 0x01, 0xA0, 0xA3, 0x55, 0x2E, 0x3F, 0xFE, 0xA7, 0x4C,
+                        0x4B, 0x3F, 0x9D, 0x4E, 0xCB, 0x78, 0x12, 0xA9, 0x42, 0xAD,
+                        0x51, 0x1F, 0x3B, 0xBD, 0x3D, 0x6A, 0xE5, 0x38, 0xB7, 0x45,
+                        0x65, 0x50, 0x30, 0x35 };
+       CK_ATTRIBUTE objTemplate[] = {
+               { CKA_CLASS, &objClass, sizeof(objClass) },
+               { CKA_KEY_TYPE, &objType, sizeof(objType) },
+               { CKA_MODULUS, pN, sizeof(pN) },
+               { CKA_PUBLIC_EXPONENT, pE, sizeof(pE) },
+               { CKA_WRAP_TEMPLATE, wrapTemplate, sizeof(wrapTemplate) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Create minimal RSA public key object
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, objTemplate, sizeof(objTemplate)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_ATTRIBUTE wrapAttribs[] = {
+               { 0, NULL_PTR, 0 },
+               { 0, NULL_PTR, 0 },
+               { 0, NULL_PTR, 0 }
+       };
+       CK_ATTRIBUTE wrapAttrib = { CKA_WRAP_TEMPLATE, NULL_PTR, 0 };
+
+       // Get number of elements
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &wrapAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(wrapAttrib.ulValueLen == 3 * sizeof(CK_ATTRIBUTE));
+
+       // Get element types and sizes
+       wrapAttrib.pValue = wrapAttribs;
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &wrapAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(wrapAttrib.ulValueLen == 3 * sizeof(CK_ATTRIBUTE));
+       for (size_t i = 0; i < 3; i++)
+       {
+               switch (wrapAttribs[i].type)
+               {
+                       case CKA_KEY_TYPE:
+                               CPPUNIT_ASSERT(wrapAttribs[i].ulValueLen == sizeof(CK_KEY_TYPE));
+                               break;
+                       case CKA_PUBLIC_EXPONENT:
+                               CPPUNIT_ASSERT(wrapAttribs[i].ulValueLen == sizeof(pE));
+                               break;
+                       case CKA_ALLOWED_MECHANISMS:
+                               CPPUNIT_ASSERT(wrapAttribs[i].ulValueLen == sizeof(allowedMechs));
+                               break;
+                       default:
+                               CPPUNIT_ASSERT(false);
+               }
+       }
+
+       // Get values
+       wrapAttribs[0].pValue = (CK_VOID_PTR)malloc(wrapAttribs[0].ulValueLen);
+       wrapAttribs[1].pValue = (CK_VOID_PTR)malloc(wrapAttribs[1].ulValueLen);
+       wrapAttribs[2].pValue = (CK_VOID_PTR)malloc(wrapAttribs[2].ulValueLen);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, &wrapAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       for (size_t i = 0; i < 3; i++)
+       {
+               switch (wrapAttribs[i].type)
+               {
+                       case CKA_KEY_TYPE:
+                               CPPUNIT_ASSERT(*(CK_KEY_TYPE*) wrapAttribs[i].pValue == CKK_SHA256_HMAC);
+                               break;
+                       case CKA_PUBLIC_EXPONENT:
+                               CPPUNIT_ASSERT(memcmp(wrapAttribs[i].pValue, pE, sizeof(pE)) == 0);
+                               break;
+                       case CKA_ALLOWED_MECHANISMS:
+                               CPPUNIT_ASSERT(memcmp(wrapAttribs[i].pValue, allowedMechs, sizeof(allowedMechs)) == 0);
+                               break;
+                       default:
+                               CPPUNIT_ASSERT(false);
+               }
+       }
+
+       free(wrapAttribs[0].pValue);
+       free(wrapAttribs[1].pValue);
+       free(wrapAttribs[2].pValue);
+}
+
+void ObjectTests::testCreateSecretKey()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_BYTE genericKey[] = {
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06
+       };
+       CK_BYTE aesKey[] = {
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06
+       };
+       CK_BYTE desKey[] = {
+               0x81, 0xdc, 0x9b, 0xdb, 0x52, 0xd0, 0x4d, 0xc2
+       };
+       CK_BYTE des2Key[] = {
+               0x81, 0xdc, 0x9b, 0xdb, 0x52, 0xd0, 0x4d, 0xc2, 0x00, 0x36,
+               0xdb, 0xd8, 0x31, 0x3e, 0xd0, 0x55
+       };
+       CK_BYTE des3Key[] = {
+               0x81, 0xdc, 0x9b, 0xdb, 0x52, 0xd0, 0x4d, 0xc2, 0x00, 0x36,
+               0xdb, 0xd8, 0x31, 0x3e, 0xd0, 0x55, 0xcc, 0x57, 0x76, 0xd1,
+               0x6a, 0x1f, 0xb6, 0xe4
+       };
+       CK_BYTE genericKCV[] = { 0x5c, 0x3b, 0x7c };
+       CK_BYTE aesKCV[] =     { 0x08, 0xbd, 0x28 };
+       CK_BYTE desKCV[] =     { 0x08, 0xa1, 0x50 };
+       CK_BYTE des2KCV[] =    { 0xa9, 0x67, 0xae };
+       CK_BYTE des3KCV[] =    { 0x5c, 0x5e, 0xec };
+
+       CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_VALUE, genericKey, sizeof(genericKey) },
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) },
+               { CKA_CLASS, &secretClass, sizeof(secretClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }
+       };
+
+       CK_BYTE pCheckValue[3];
+       CK_ATTRIBUTE attribKCV[] = {
+               { CKA_CHECK_VALUE, pCheckValue, sizeof(pCheckValue) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, attribKCV, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribKCV[0].ulValueLen == 3);
+       CPPUNIT_ASSERT(memcmp(pCheckValue, genericKCV, 3) == 0);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       keyType = CKK_AES;
+       attribs[0].pValue = aesKey;
+       attribs[0].ulValueLen = sizeof(aesKey);
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, attribKCV, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribKCV[0].ulValueLen == 3);
+       CPPUNIT_ASSERT(memcmp(pCheckValue, aesKCV, 3) == 0);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       keyType = CKK_DES;
+       attribs[0].pValue = desKey;
+       attribs[0].ulValueLen = sizeof(desKey);
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, attribKCV, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribKCV[0].ulValueLen == 3);
+       CPPUNIT_ASSERT(memcmp(pCheckValue, desKCV, 3) == 0);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       keyType = CKK_DES2;
+       attribs[0].pValue = des2Key;
+       attribs[0].ulValueLen = sizeof(des2Key);
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, attribKCV, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribKCV[0].ulValueLen == 3);
+       CPPUNIT_ASSERT(memcmp(pCheckValue, des2KCV, 3) == 0);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       keyType = CKK_DES3;
+       attribs[0].pValue = des3Key;
+       attribs[0].ulValueLen = sizeof(des3Key);
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hObject, attribKCV, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(attribKCV[0].ulValueLen == 3);
+       CPPUNIT_ASSERT(memcmp(pCheckValue, des3KCV, 3) == 0);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession,hObject) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
diff --git a/SoftHSMv2/src/lib/test/ObjectTests.h b/SoftHSMv2/src/lib/test/ObjectTests.h
new file mode 100644 (file)
index 0000000..b15ae48
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ ObjectTests.h
+
+ Contains test cases to C_CreateObject, C_CopyObject, C_DestroyObject,
+ C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit,
+ C_FindObjects, C_FindObjectsFinal, C_GenerateKeyPair
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_OBJECTTESTS_H
+#define _SOFTHSM_V2_OBJECTTESTS_H
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class ObjectTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(ObjectTests);
+       CPPUNIT_TEST(testCreateObject);
+       CPPUNIT_TEST(testCopyObject);
+       CPPUNIT_TEST(testDestroyObject);
+       CPPUNIT_TEST(testGetObjectSize);
+       CPPUNIT_TEST(testGetAttributeValue);
+       CPPUNIT_TEST(testSetAttributeValue);
+       CPPUNIT_TEST(testFindObjects);
+       CPPUNIT_TEST(testGenerateKeys);
+       CPPUNIT_TEST(testCreateCertificates);
+       CPPUNIT_TEST(testDefaultDataAttributes);
+       CPPUNIT_TEST(testDefaultX509CertAttributes);
+       CPPUNIT_TEST(testDefaultRSAPubAttributes);
+       CPPUNIT_TEST(testDefaultRSAPrivAttributes);
+       CPPUNIT_TEST(testAlwaysNeverAttribute);
+       CPPUNIT_TEST(testSensitiveAttributes);
+       CPPUNIT_TEST(testGetInvalidAttribute);
+       CPPUNIT_TEST(testAllowedMechanisms);
+       CPPUNIT_TEST(testReAuthentication);
+       CPPUNIT_TEST(testTemplateAttribute);
+       CPPUNIT_TEST(testCreateSecretKey);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testCreateObject();
+       void testCopyObject();
+       void testDestroyObject();
+       void testGetObjectSize();
+       void testGetAttributeValue();
+       void testSetAttributeValue();
+       void testFindObjects();
+       void testGenerateKeys();
+       void testCreateCertificates();
+       void testDefaultDataAttributes();
+       void testDefaultX509CertAttributes();
+       void testDefaultRSAPubAttributes();
+       void testDefaultRSAPrivAttributes();
+       void testAlwaysNeverAttribute();
+       void testSensitiveAttributes();
+       void testGetInvalidAttribute();
+       void testReAuthentication();
+       void testAllowedMechanisms();
+       void testTemplateAttribute();
+       void testCreateSecretKey();
+
+protected:
+       void checkCommonObjectAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_OBJECT_CLASS objectClass
+       );
+       void checkCommonStorageObjectAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BBOOL bToken,
+               CK_BBOOL bPrivate,
+               CK_BBOOL bModifiable,
+               CK_UTF8CHAR_PTR pLabel, CK_ULONG ulLabelLen,
+               CK_BBOOL bCopyable,
+               CK_BBOOL bDestroyable
+       );
+       void checkDataObjectAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_UTF8CHAR_PTR pApplication, CK_ULONG ulApplicationLen,
+               CK_BYTE_PTR pObjectID, CK_ULONG ulObjectIdLen,
+               CK_BYTE_PTR pValue, CK_ULONG ulValueLen
+       );
+       void checkCommonCertificateObjectAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_CERTIFICATE_TYPE certType,
+               CK_BBOOL bTrusted,
+               CK_ULONG ulCertificateCategory,
+               CK_BYTE_PTR pCheckValue, CK_ULONG ulCheckValueLen,
+               CK_DATE startDate, CK_ULONG ulStartDateLen,
+               CK_DATE endDate, CK_ULONG ulEndDateLen
+       );
+       void checkX509CertificateObjectAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen,
+               CK_BYTE_PTR pId, CK_ULONG ulIdLen,
+               CK_BYTE_PTR pIssuer, CK_ULONG ulIssuerLen,
+               CK_BYTE_PTR pSerialNumber, CK_ULONG ulSerialNumberLen,
+               CK_BYTE_PTR pValue, CK_ULONG ulValueLen,
+               CK_BYTE_PTR pUrl, CK_ULONG ulUrlLen,
+               CK_BYTE_PTR pHashOfSubjectPublicKey, CK_ULONG ulHashOfSubjectPublicKeyLen,
+               CK_BYTE_PTR pHashOfIssuerPublicKey, CK_ULONG ulHashOfIssuerPublicKeyLen,
+               CK_ULONG ulJavaMidpSecurityDomain,
+               CK_MECHANISM_TYPE nameHashAlgorithm
+       );
+       void checkCommonKeyAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_KEY_TYPE keyType,
+               CK_BYTE_PTR pId, CK_ULONG ulIdLen,
+               CK_DATE startDate, CK_ULONG ulStartDateLen,
+               CK_DATE endDate, CK_ULONG ulEndDateLen,
+               CK_BBOOL bDerive,
+               CK_BBOOL bLocal,
+               CK_MECHANISM_TYPE keyMechanismType,
+               CK_MECHANISM_TYPE_PTR pAllowedMechanisms, CK_ULONG ulAllowedMechanismsLen /* len = count * sizeof(CK_MECHANISM_TYPE) */
+       );
+       void checkCommonPublicKeyAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen,
+               CK_BBOOL bEncrypt,
+               CK_BBOOL bVerify,
+               CK_BBOOL bVerifyRecover,
+               CK_BBOOL bWrap,
+               CK_BBOOL bTrusted,
+               CK_ATTRIBUTE_PTR pWrapTemplate, CK_ULONG ulWrapTemplateLen /* len = count * sizeof(CK_ATTRIBUTE) */
+       );
+       void checkCommonPrivateKeyAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BYTE_PTR pSubject, CK_ULONG ulSubjectLen,
+               CK_BBOOL bSensitive,
+               CK_BBOOL bDecrypt,
+               CK_BBOOL bSign,
+               CK_BBOOL bSignRecover,
+               CK_BBOOL bUnwrap,
+               CK_BBOOL bExtractable,
+               CK_BBOOL bAlwaysSensitive,
+               CK_BBOOL bNeverExtractable,
+               CK_BBOOL bWrapWithTrusted,
+               CK_ATTRIBUTE_PTR pUnwrapTemplate, CK_ULONG ulUnwrapTemplateLen, /* len = count * sizeof(CK_ATTRIBUTE) */
+               CK_BBOOL bAlwaysAuthenticate
+       );
+       void checkCommonRSAPublicKeyAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BYTE_PTR pModulus, CK_ULONG ulModulusLen,
+               CK_ULONG ulModulusBits,
+               CK_BYTE_PTR pPublicExponent, CK_ULONG ulPublicExponentLen
+       );
+       void checkCommonRSAPrivateKeyAttributes
+       (       CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+               CK_BYTE_PTR pModulus, CK_ULONG ulModulusLen,
+               CK_BYTE_PTR pPublicExponent, CK_ULONG ulPublicExponentLen,
+               CK_BYTE_PTR pPrivateExponent, CK_ULONG ulPrivateExponentLen,
+               CK_BYTE_PTR pPrime1, CK_ULONG ulPrime1Len,
+               CK_BYTE_PTR pPrime2, CK_ULONG ulPrime2Len,
+               CK_BYTE_PTR pExponent1, CK_ULONG ulExponent1Len,
+               CK_BYTE_PTR pExponent2, CK_ULONG ulExponent2Len,
+               CK_BYTE_PTR pCoefficient, CK_ULONG ulCoefficientLen
+       );
+
+       CK_RV createDataObjectMinimal(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject);
+       CK_RV createDataObjectMCD(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_BBOOL bModifiable, CK_BBOOL bCopyable, CK_BBOOL bDestroyable, CK_OBJECT_HANDLE &hObject);
+       CK_RV createDataObjectNormal(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject);
+
+       CK_RV createCertificateObjectIncomplete(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject);
+       CK_RV createCertificateObjectX509(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hObject);
+
+       CK_RV generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+};
+
+#endif // !_SOFTHSM_V2_OBJECTTESTS_H
diff --git a/SoftHSMv2/src/lib/test/README b/SoftHSMv2/src/lib/test/README
new file mode 100644 (file)
index 0000000..d9e6cce
--- /dev/null
@@ -0,0 +1,17 @@
+To build for test of SoftHSM with static linking:
+make p11test
+
+To build for testing another p11 module provided as shared library:
+make p11test_DEPENDENCIES= p11test_LDADD= CPPFLAGS=-DP11M=\\\"./p11m.so\\\" p11test
+Substitute ./p11m.so with the path to your shared library.
+Note that nothing else of SoftHSMv2 has to be built in order to build the test of an external p11.
+
+To run the test with first a test summary and then specific output of each failure:
+./p11test
+
+To get output of each test after it is executed:
+./p11test direct
+
+To run a specific test:
+./p11test ObjectTests::testArrayAttribute
+Substitute 'ObjectTests::testArrayAttribute' with the test you want to run.
diff --git a/SoftHSMv2/src/lib/test/RandomTests.cpp b/SoftHSMv2/src/lib/test/RandomTests.cpp
new file mode 100644 (file)
index 0000000..8fe25bc
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ RandomTests.cpp
+
+ Contains test cases to C_SeedRandom and C_GenerateRandom
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "RandomTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RandomTests);
+
+void RandomTests::testSeedRandom()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_BYTE seed[] = {"Some random data"};
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_SeedRandom(CK_INVALID_HANDLE, seed, sizeof(seed)) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SeedRandom(hSession, NULL_PTR, sizeof(seed)) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_SeedRandom(hSession, seed, sizeof(seed)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SeedRandom(hSession, seed, sizeof(seed)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void RandomTests::testGenerateRandom()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_BYTE randomData[40];
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(CK_INVALID_HANDLE, randomData, 40) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, NULL_PTR, 40) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, randomData, 40) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, randomData, 40) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
diff --git a/SoftHSMv2/src/lib/test/RandomTests.h b/SoftHSMv2/src/lib/test/RandomTests.h
new file mode 100644 (file)
index 0000000..4b7b062
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ RandomTests.h
+
+ Contains test cases to C_SeedRandom and C_GenerateRandom
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RANDOMTESTS_H
+#define _SOFTHSM_V2_RANDOMTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class RandomTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(RandomTests);
+       CPPUNIT_TEST(testSeedRandom);
+       CPPUNIT_TEST(testGenerateRandom);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testSeedRandom();
+       void testGenerateRandom();
+};
+
+#endif // !_SOFTHSM_V2_RANDOMTESTS_H
diff --git a/SoftHSMv2/src/lib/test/SessionTests.cpp b/SoftHSMv2/src/lib/test/SessionTests.cpp
new file mode 100644 (file)
index 0000000..756106a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionTests.cpp
+
+ Contains test cases to C_OpenSession, C_CloseSession, C_CloseAllSessions, and
+ C_GetSessionInfo
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SessionTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SessionTests);
+
+void SessionTests::testOpenSession()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+
+    // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+    rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_invalidSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_notInitializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_TOKEN_NOT_RECOGNIZED);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, 0, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_PARALLEL_NOT_SUPPORTED);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void SessionTests::testCloseSession()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession + 1) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+}
+
+void SessionTests::testCloseAllSessions()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_SESSION_INFO info;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_CloseAllSessions(m_initializedTokenSlotID) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_CloseAllSessions(m_invalidSlotID) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_CloseAllSessions(m_notInitializedTokenSlotID) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession, &info) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_CloseAllSessions(m_initializedTokenSlotID) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+}
+
+void SessionTests::testGetSessionInfo()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+       CK_SESSION_INFO info;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+    rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession, &info) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+    rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    rv = CRYPTOKI_F_PTR( C_GetSessionInfo(CK_INVALID_HANDLE, &info) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+    rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession + 1, &info) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession, NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+    rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession, &info) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    CPPUNIT_ASSERT(info.state == CKS_RO_PUBLIC_SESSION);
+       CPPUNIT_ASSERT(info.flags == CKF_SERIAL_SESSION);
+
+    rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+    rv = CRYPTOKI_F_PTR( C_GetSessionInfo(hSession, &info) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+}
diff --git a/SoftHSMv2/src/lib/test/SessionTests.h b/SoftHSMv2/src/lib/test/SessionTests.h
new file mode 100644 (file)
index 0000000..c940ab0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ SessionTests.h
+
+ Contains test cases to C_OpenSession, C_CloseSession, C_CloseAllSessions, and
+ C_GetSessionInfo
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SESSIONTESTS_H
+#define _SOFTHSM_V2_SESSIONTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class SessionTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(SessionTests);
+       CPPUNIT_TEST(testOpenSession);
+       CPPUNIT_TEST(testCloseSession);
+       CPPUNIT_TEST(testCloseAllSessions);
+       CPPUNIT_TEST(testGetSessionInfo);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testOpenSession();
+       void testCloseSession();
+       void testCloseAllSessions();
+       void testGetSessionInfo();
+};
+
+#endif // !_SOFTHSM_V2_SESSIONTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/SignVerifyTests.cpp b/SoftHSMv2/src/lib/test/SignVerifyTests.cpp
new file mode 100644 (file)
index 0000000..06dbf95
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ SignVerifyTests.cpp
+
+ Contains test cases for:
+        C_SignInit
+        C_Sign
+        C_SignUpdate
+        C_SignFinal
+        C_VerifyInit
+        C_Verify
+        C_VerifyUpdate
+        C_VerifyFinal
+
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SignVerifyTests.h"
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SignVerifyTests);
+
+CK_RV SignVerifyTests::generateRSA(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_KEY_TYPE keyType = CKK_RSA;
+       CK_ULONG bits = 1536;
+       CK_BYTE pubExp[] = {0x01, 0x00, 0x01};
+       CK_BYTE label[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_LABEL, &label[0], sizeof(label) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_WRAP, &bFalse, sizeof(bFalse) },
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) },
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) },
+               { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_LABEL, &label[0], sizeof(label) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_UNWRAP, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }
+       };
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                                                        pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        &hPuk, &hPrk) );
+}
+
+#ifdef WITH_ECC
+CK_RV SignVerifyTests::generateEC(const char* curve, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk)
+{
+       CK_MECHANISM mechanism = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_KEY_TYPE keyType = CKK_EC;
+       CK_BYTE oidP256[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 };
+       CK_BYTE oidP384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 };
+       CK_BYTE oidP521[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 };
+       CK_BYTE label[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+
+       CK_ATTRIBUTE pukAttribs[] = {
+               { CKA_EC_PARAMS, NULL, 0 },
+               { CKA_LABEL, &label[0], sizeof(label) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_WRAP, &bFalse, sizeof(bFalse) },
+               { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) },
+               { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) }
+       };
+       CK_ATTRIBUTE prkAttribs[] = {
+               { CKA_LABEL, &label[0], sizeof(label) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_UNWRAP, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) },
+               { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) },
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }
+       };
+
+       /* Select the curve */
+       if (strcmp(curve, "P-256") == 0)
+       {
+               pukAttribs[0].pValue = oidP256;
+               pukAttribs[0].ulValueLen = sizeof(oidP256);
+       }
+       else if (strcmp(curve, "P-384") == 0)
+       {
+               pukAttribs[0].pValue = oidP384;
+               pukAttribs[0].ulValueLen = sizeof(oidP384);
+       }
+       else if (strcmp(curve, "P-521") == 0)
+       {
+               pukAttribs[0].pValue = oidP521;
+               pukAttribs[0].ulValueLen = sizeof(oidP521);
+       }
+       else
+       {
+               return CKR_GENERAL_ERROR;
+       }
+
+       hPuk = CK_INVALID_HANDLE;
+       hPrk = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                                                        pukAttribs, sizeof(pukAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        prkAttribs, sizeof(prkAttribs)/sizeof(CK_ATTRIBUTE),
+                                                        &hPuk, &hPrk) );
+}
+#endif
+
+void SignVerifyTests::signVerifySingle(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param /* = NULL_PTR */, CK_ULONG paramLen /* = 0 */)
+{
+       CK_RV rv;
+       CK_MECHANISM mechanism = { mechanismType, param, paramLen };
+       CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,0x0C, 0x0D, 0x0F };
+       CK_BYTE signature[256];
+       CK_ULONG ulSignatureLen = 0;
+
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession,&mechanism,hPrivateKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulSignatureLen = sizeof(signature);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession,data,sizeof(data),signature,&ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Verify(hSession,data,sizeof(data),signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // verify again, but now change the input that is being signed.
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       data[0] = 0xff;
+       rv = CRYPTOKI_F_PTR( C_Verify(hSession,data,sizeof(data),signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_SIGNATURE_INVALID);
+}
+
+void SignVerifyTests::signVerifySingleData(size_t dataSize, CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param /* = NULL_PTR */, CK_ULONG paramLen /* = 0 */)
+{
+       CK_RV rv;
+       CK_MECHANISM mechanism = { mechanismType, param, paramLen };
+       CK_BYTE *data = (CK_BYTE*)malloc(dataSize);
+       CK_BYTE signature[1024];
+       CK_ULONG ulSignatureLen = 0;
+       unsigned i;
+
+       CPPUNIT_ASSERT(data != NULL);
+
+       for (i=0;i<dataSize;i++)
+               data[i] = i;
+
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession,&mechanism,hPrivateKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulSignatureLen = sizeof(signature);
+       rv = CRYPTOKI_F_PTR( C_Sign(hSession,data,dataSize,signature,&ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Verify(hSession,data,dataSize,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // verify again, but now change the input that is being signed.
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       data[0] = 0xff;
+       rv = CRYPTOKI_F_PTR( C_Verify(hSession,data,dataSize,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_SIGNATURE_INVALID);
+
+       free(data);
+}
+
+void SignVerifyTests::signVerifyMulti(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param /* = NULL_PTR */, CK_ULONG paramLen /* = 0 */)
+{
+       CK_RV rv;
+       CK_MECHANISM mechanism = { mechanismType, param, paramLen };
+       CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,0x0C, 0x0D, 0x0F };
+       CK_BYTE signature[256];
+       CK_ULONG ulSignatureLen = 0;
+
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession,&mechanism,hPrivateKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv =CRYPTOKI_F_PTR( C_SignUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulSignatureLen = sizeof(signature);
+       rv =CRYPTOKI_F_PTR( C_SignFinal(hSession,signature,&ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyFinal(hSession,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // verify again, but now change the input that is being signed.
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hPublicKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       data[0] = 0xff;
+       rv = CRYPTOKI_F_PTR( C_VerifyUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyFinal(hSession,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_SIGNATURE_INVALID);
+}
+
+void SignVerifyTests::testRsaSignVerify()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+       CK_RSA_PKCS_PSS_PARAMS params[] = {
+               { CKM_SHA_1,  CKG_MGF1_SHA1,   0  },
+               { CKM_SHA224, CKG_MGF1_SHA224, 28 },
+               { CKM_SHA256, CKG_MGF1_SHA256, 32 },
+               { CKM_SHA384, CKG_MGF1_SHA384, 0  },
+               { CKM_SHA512, CKG_MGF1_SHA512, 0  }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       // Public Session keys
+       rv = generateRSA(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       signVerifySingle(CKM_RSA_PKCS, hSessionRO, hPuk,hPrk);
+       signVerifySingle(CKM_RSA_X_509, hSessionRO, hPuk,hPrk);
+#ifndef WITH_FIPS
+       signVerifyMulti(CKM_MD5_RSA_PKCS, hSessionRO, hPuk,hPrk);
+#endif
+       signVerifyMulti(CKM_SHA1_RSA_PKCS, hSessionRO, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA224_RSA_PKCS, hSessionRO, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA256_RSA_PKCS, hSessionRO, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA384_RSA_PKCS, hSessionRO, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA512_RSA_PKCS, hSessionRO, hPuk,hPrk);
+
+#ifdef WITH_RAW_PSS
+       signVerifySingleData(20, CKM_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[0], sizeof(params[0]));
+       signVerifySingleData(28, CKM_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[1], sizeof(params[1]));
+       signVerifySingleData(32, CKM_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[2], sizeof(params[2]));
+       signVerifySingleData(48, CKM_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[3], sizeof(params[3]));
+       signVerifySingleData(64, CKM_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[4], sizeof(params[4]));
+#endif
+
+       signVerifyMulti(CKM_SHA1_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[0], sizeof(params[0]));
+       signVerifyMulti(CKM_SHA224_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[1], sizeof(params[1]));
+       signVerifyMulti(CKM_SHA256_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[2], sizeof(params[2]));
+       signVerifyMulti(CKM_SHA384_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[3], sizeof(params[3]));
+       signVerifyMulti(CKM_SHA512_RSA_PKCS_PSS, hSessionRO, hPuk,hPrk, &params[4], sizeof(params[4]));
+
+       // Private Session Keys
+       rv = generateRSA(hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       signVerifySingle(CKM_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifySingle(CKM_RSA_X_509, hSessionRW, hPuk,hPrk);
+#ifndef WITH_FIPS
+       signVerifyMulti(CKM_MD5_RSA_PKCS, hSessionRW, hPuk,hPrk);
+#endif
+       signVerifyMulti(CKM_SHA1_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA224_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA256_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA384_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA512_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA1_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[0], sizeof(params[0]));
+       signVerifyMulti(CKM_SHA224_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[1], sizeof(params[1]));
+       signVerifyMulti(CKM_SHA256_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[2], sizeof(params[2]));
+       signVerifyMulti(CKM_SHA384_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[3], sizeof(params[3]));
+       signVerifyMulti(CKM_SHA512_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[4], sizeof(params[4]));
+
+       // Public Token Keys
+       rv = generateRSA(hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       signVerifySingle(CKM_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifySingle(CKM_RSA_X_509, hSessionRW, hPuk,hPrk);
+#ifndef WITH_FIPS
+       signVerifyMulti(CKM_MD5_RSA_PKCS, hSessionRW, hPuk,hPrk);
+#endif
+       signVerifyMulti(CKM_SHA1_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA224_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA256_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA384_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA512_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA1_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[0], sizeof(params[0]));
+       signVerifyMulti(CKM_SHA224_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[1], sizeof(params[1]));
+       signVerifyMulti(CKM_SHA256_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[2], sizeof(params[2]));
+       signVerifyMulti(CKM_SHA384_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[3], sizeof(params[3]));
+       signVerifyMulti(CKM_SHA512_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[4], sizeof(params[4]));
+
+       // Private Token Keys
+       rv = generateRSA(hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       signVerifySingle(CKM_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifySingle(CKM_RSA_X_509, hSessionRW, hPuk,hPrk);
+#ifndef WITH_FIPS
+       signVerifyMulti(CKM_MD5_RSA_PKCS, hSessionRW, hPuk,hPrk);
+#endif
+       signVerifyMulti(CKM_SHA1_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA224_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA256_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA384_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA512_RSA_PKCS, hSessionRW, hPuk,hPrk);
+       signVerifyMulti(CKM_SHA1_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[0], sizeof(params[0]));
+       signVerifyMulti(CKM_SHA224_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[1], sizeof(params[1]));
+       signVerifyMulti(CKM_SHA256_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[2], sizeof(params[2]));
+       signVerifyMulti(CKM_SHA384_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[3], sizeof(params[3]));
+       signVerifyMulti(CKM_SHA512_RSA_PKCS_PSS, hSessionRW, hPuk,hPrk, &params[4], sizeof(params[4]));
+}
+
+#ifdef WITH_ECC
+void SignVerifyTests::testEcSignVerify()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hPuk = CK_INVALID_HANDLE;
+       CK_OBJECT_HANDLE hPrk = CK_INVALID_HANDLE;
+
+       // Public Session keys
+       rv = generateEC("P-256", hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-384", hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-521", hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+
+       // Private Session Keys
+       rv = generateEC("P-256", hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-384", hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-521", hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+
+       // Public Token Keys
+       rv = generateEC("P-256", hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-384", hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-521", hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+
+       // Private Token Keys
+       rv = generateEC("P-256", hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-384", hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+       rv = generateEC("P-521", hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk,hPrk);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       signVerifySingle(CKM_ECDSA, hSessionRO, hPuk,hPrk);
+}
+#endif
+
+CK_RV SignVerifyTests::generateKey(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keyType, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+#ifndef WITH_BOTAN
+#define GEN_KEY_LEN    75
+#else
+#define GEN_KEY_LEN    64
+#endif
+       CK_RV rv;
+       CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+       CK_BYTE val[GEN_KEY_LEN];
+       //CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_BYTE oid[] = { 0x06, 0x07, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x1F, 0x00 };
+       CK_ATTRIBUTE kAttribs[] = {
+               { CKA_CLASS, &keyClass, sizeof(keyClass) },
+               { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE, val, sizeof(val) },
+               { CKA_GOST28147_PARAMS, oid, sizeof(oid) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, val, GEN_KEY_LEN) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       hKey = CK_INVALID_HANDLE;
+       if (keyType == CKK_GOST28147)
+       {
+               return CRYPTOKI_F_PTR( C_CreateObject(hSession, kAttribs, 9, &hKey) );
+       }
+       else
+       {
+               return CRYPTOKI_F_PTR( C_CreateObject(hSession, kAttribs, 8, &hKey) );
+       }
+}
+
+CK_RV SignVerifyTests::generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES2_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+CK_RV SignVerifyTests::generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES3_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+CK_RV SignVerifyTests::generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_ULONG bytes = 16;
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &bytes, sizeof(bytes) }
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+void SignVerifyTests::macSignVerify(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
+{
+       CK_RV rv;
+       CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
+       CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,0x0C, 0x0D, 0x0F };
+       CK_BYTE signature[256];
+       CK_ULONG ulSignatureLen = 0;
+
+       rv = CRYPTOKI_F_PTR( C_SignInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv =CRYPTOKI_F_PTR( C_SignUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       ulSignatureLen = sizeof(signature);
+       rv =CRYPTOKI_F_PTR( C_SignFinal(hSession,signature,&ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyFinal(hSession,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // verify again, but now change the input that is being signed.
+       rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       data[0] = 0xff;
+       rv = CRYPTOKI_F_PTR( C_VerifyUpdate(hSession,data,sizeof(data)) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_VerifyFinal(hSession,signature,ulSignatureLen) );
+       CPPUNIT_ASSERT(rv==CKR_SIGNATURE_INVALID);
+}
+
+void SignVerifyTests::testMacSignVerify()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // Public Session keys
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+#ifndef WITH_FIPS
+       rv = generateKey(hSessionRW,CKK_MD5_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_MD5_HMAC, hSessionRO, hKey);
+#endif
+
+       rv = generateKey(hSessionRW,CKK_SHA_1_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA_1_HMAC, hSessionRO, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA224_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA224_HMAC, hSessionRO, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA256_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA256_HMAC, hSessionRO, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA384_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA384_HMAC, hSessionRO, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA512_HMAC,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA512_HMAC, hSessionRO, hKey);
+
+#ifdef WITH_GOST
+       rv = generateKey(hSessionRW,CKK_GOST28147,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_GOSTR3411_HMAC, hSessionRO, hKey);
+#endif
+
+       rv = generateDes2Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateDes3Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateAesKey(hSessionRW,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_AES_CMAC, hSessionRO, hKey);
+
+       // Private Session Keys
+#ifndef WITH_FIPS
+       rv = generateKey(hSessionRW,CKK_MD5_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_MD5_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateKey(hSessionRW,CKK_SHA_1_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA_1_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA224_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA224_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA256_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA256_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA384_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA384_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA512_HMAC,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA512_HMAC, hSessionRW, hKey);
+
+#ifdef WITH_GOST
+       rv = generateKey(hSessionRW,CKK_GOST28147,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_GOSTR3411_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateDes2Key(hSessionRW,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateDes3Key(hSessionRW,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateAesKey(hSessionRW,IN_SESSION,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_AES_CMAC, hSessionRO, hKey);
+
+       // Public Token Keys
+#ifndef WITH_FIPS
+       rv = generateKey(hSessionRW,CKK_MD5_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_MD5_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateKey(hSessionRW,CKK_SHA_1_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA_1_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA224_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA224_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA256_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA256_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA384_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA384_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA512_HMAC,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA512_HMAC, hSessionRW, hKey);
+
+#ifdef WITH_GOST
+       rv = generateKey(hSessionRW,CKK_GOST28147,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_GOSTR3411_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateDes2Key(hSessionRW,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateDes3Key(hSessionRW,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateAesKey(hSessionRW,ON_TOKEN,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_AES_CMAC, hSessionRO, hKey);
+
+       // Private Token Keys
+#ifndef WITH_FIPS
+       rv = generateKey(hSessionRW,CKK_MD5_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_MD5_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateKey(hSessionRW,CKK_SHA_1_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA_1_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA224_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA224_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA256_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA256_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA384_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA384_HMAC, hSessionRW, hKey);
+
+       rv = generateKey(hSessionRW,CKK_SHA512_HMAC,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_SHA512_HMAC, hSessionRW, hKey);
+
+#ifdef WITH_GOST
+       rv = generateKey(hSessionRW,CKK_GOST28147,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_GOSTR3411_HMAC, hSessionRW, hKey);
+#endif
+
+       rv = generateDes2Key(hSessionRW,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateDes3Key(hSessionRW,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_DES3_CMAC, hSessionRO, hKey);
+
+       rv = generateAesKey(hSessionRW,ON_TOKEN,IS_PRIVATE,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       macSignVerify(CKM_AES_CMAC, hSessionRO, hKey);
+}
+
diff --git a/SoftHSMv2/src/lib/test/SignVerifyTests.h b/SoftHSMv2/src/lib/test/SignVerifyTests.h
new file mode 100644 (file)
index 0000000..a251218
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ SignVerifyTests.h
+
+ Contains test cases to C_SignInit,C_Sign,C_SignUpdate,C_SignFinal,
+ C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SIGNVERIFYTESTS_H
+#define _SOFTHSM_V2_SIGNVERIFYTESTS_H
+
+#include "config.h"
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class SignVerifyTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(SignVerifyTests);
+       CPPUNIT_TEST(testRsaSignVerify);
+#ifdef WITH_ECC
+       CPPUNIT_TEST(testEcSignVerify);
+#endif
+       CPPUNIT_TEST(testMacSignVerify);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testRsaSignVerify();
+#ifdef WITH_ECC
+       void testEcSignVerify();
+#endif
+       void testMacSignVerify();
+
+protected:
+       CK_RV generateRSA(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+#ifdef WITH_ECC
+       CK_RV generateEC(const char* curve, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);
+#endif
+       void signVerifySingle(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param = NULL_PTR, CK_ULONG paramLen = 0);
+       void signVerifySingleData(size_t dataSize, CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param = NULL_PTR, CK_ULONG paramLen = 0);
+       void signVerifyMulti(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param = NULL_PTR, CK_ULONG paramLen = 0);
+       CK_RV generateKey(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keyType, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       void macSignVerify(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey);
+};
+
+#endif // !_SOFTHSM_V2_SIGNVERIFYTESTS_H
diff --git a/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp b/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp
new file mode 100644 (file)
index 0000000..f301c73
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricAlgorithmTests.cpp
+
+ Contains test cases for symmetrical algorithms (i.e., AES and DES)
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <climits>
+//#include <iomanip>
+#include "SymmetricAlgorithmTests.h"
+
+// CKA_TOKEN
+const CK_BBOOL ON_TOKEN = CK_TRUE;
+const CK_BBOOL IN_SESSION = CK_FALSE;
+
+// CKA_PRIVATE
+const CK_BBOOL IS_PRIVATE = CK_TRUE;
+const CK_BBOOL IS_PUBLIC = CK_FALSE;
+
+#define NR_OF_BLOCKS_IN_TEST 0x10001
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SymmetricAlgorithmTests);
+
+CK_RV SymmetricAlgorithmTests::generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_ULONG bytes = 16;
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bTrue, sizeof(bTrue) },
+               { CKA_UNWRAP, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &bytes, sizeof(bytes) },
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+#ifndef WITH_FIPS
+CK_RV SymmetricAlgorithmTests::generateDesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+CK_RV SymmetricAlgorithmTests::generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES2_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+#endif
+
+CK_RV SymmetricAlgorithmTests::generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_DES3_KEY_GEN, NULL_PTR, 0 };
+       // CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+       };
+
+       hKey = CK_INVALID_HANDLE;
+       return CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                            keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+                            &hKey) );
+}
+
+void SymmetricAlgorithmTests::encryptDecrypt(
+               const CK_MECHANISM_TYPE mechanismType,
+               const size_t blockSize,
+               const CK_SESSION_HANDLE hSession,
+               const CK_OBJECT_HANDLE hKey,
+               const size_t messageSize,
+               const bool isSizeOK)
+{
+       class PartSize {// class to get random size for part
+       private:        // we want to know for sure that no part length is causing any problem.
+               const int blockSize;
+               const unsigned* pRandom;// point to memory with random data. We are using the data to be encrypted.
+               const unsigned* pBack;// point to memory where random data ends.
+               int current;// the current size.
+       public:
+               PartSize(
+                               const int _blockSize,
+                               const std::vector<CK_BYTE>* pvData) :
+                                       blockSize(_blockSize),
+                                       pRandom((const unsigned*)&pvData->front()),
+                                       pBack((const unsigned*)&pvData->back()),
+                                       current(blockSize*4){};
+               int getCurrent() {// current part size
+                       return current;
+               }
+               int getNext() {// get next part size.
+                       // Check if we do not have more random data
+                       if ((pRandom+sizeof(unsigned)-1) > pBack) {
+                               current = blockSize*4;
+                               return current;
+                       }
+                       const unsigned random(*(pRandom++));
+                       // Bit shift to handle 32- and 64-bit systems.
+                       // Just want a simple random part length,
+                       // not a perfect random number (bit shifting will
+                       // give some loss of precision).
+                       current = ((unsigned long)random >> 20)*blockSize*0x100/(UINT_MAX >> 20) + 1;
+                       //std::cout << "New random " << std::hex << random << " current " << std::hex << std::setfill('0') << std::setw(4) << current << " block size " << std::hex << blockSize << std::endl;
+                       return current;
+               }
+       };
+
+       const std::vector<CK_BYTE> vData(messageSize);
+       std::vector<CK_BYTE> vEncryptedData;
+       std::vector<CK_BYTE> vEncryptedDataParted;
+       PartSize partSize(blockSize, &vData);
+
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_GenerateRandom(hSession, (CK_BYTE_PTR)&vData.front(), messageSize) ) );
+
+       const CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
+       CK_MECHANISM_PTR pMechanism((CK_MECHANISM_PTR)&mechanism);
+       CK_AES_CTR_PARAMS ctrParams =
+       {
+               32,
+               {
+                       0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+               }
+       };
+       CK_BYTE gcmIV[] = {
+               0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE,
+               0xDB, 0xAD, 0xDE, 0xCA, 0xF8, 0x88
+       };
+       CK_BYTE gcmAAD[] = {
+               0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF,
+               0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF,
+               0xAB, 0xAD, 0xDA, 0xD2
+       };
+       CK_GCM_PARAMS gcmParams =
+       {
+               &gcmIV[0],
+               sizeof(gcmIV),
+               sizeof(gcmIV)*8,
+               &gcmAAD[0],
+               sizeof(gcmAAD),
+               16*8
+       };
+
+       switch (mechanismType)
+       {
+               case CKM_DES_CBC:
+               case CKM_DES_CBC_PAD:
+               case CKM_DES3_CBC:
+               case CKM_DES3_CBC_PAD:
+               case CKM_AES_CBC:
+               case CKM_AES_CBC_PAD:
+                       pMechanism->pParameter = (CK_VOID_PTR)&vData.front();
+                       pMechanism->ulParameterLen = blockSize;
+                       break;
+               case CKM_AES_CTR:
+                       pMechanism->pParameter = &ctrParams;
+                       pMechanism->ulParameterLen = sizeof(ctrParams);
+                       break;
+               case CKM_AES_GCM:
+                       pMechanism->pParameter = &gcmParams;
+                       pMechanism->ulParameterLen = sizeof(gcmParams);
+                       break;
+               default:
+                       break;
+       }
+
+       // Single-part encryption
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_EncryptInit(hSession,pMechanism,hKey) ) );
+       {
+               CK_ULONG ulEncryptedDataLen;
+               const CK_RV rv( CRYPTOKI_F_PTR( C_Encrypt(hSession,(CK_BYTE_PTR)&vData.front(),messageSize,NULL_PTR,&ulEncryptedDataLen) ) );
+               if ( isSizeOK ) {
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+                       vEncryptedData.resize(ulEncryptedDataLen);
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_Encrypt(hSession,(CK_BYTE_PTR)&vData.front(),messageSize,&vEncryptedData.front(),&ulEncryptedDataLen) ) );
+                       vEncryptedData.resize(ulEncryptedDataLen);
+               } else {
+                       CPPUNIT_ASSERT_EQUAL_MESSAGE("C_Encrypt should fail with C_CKR_DATA_LEN_RANGE", (CK_RV)CKR_DATA_LEN_RANGE, rv);
+                       vEncryptedData = vData;
+               }
+       }
+
+       // Multi-part encryption
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_EncryptInit(hSession,pMechanism,hKey) ) );
+
+       for ( std::vector<CK_BYTE>::const_iterator i(vData.begin()); i<vData.end(); i+=partSize.getCurrent() ) {
+               const CK_ULONG lPartLen( i+partSize.getNext()<vData.end() ? partSize.getCurrent() : vData.end()-i );
+               CK_ULONG ulEncryptedPartLen;
+               CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_EncryptUpdate(hSession,(CK_BYTE_PTR)&(*i),lPartLen,NULL_PTR,&ulEncryptedPartLen) ) );
+               const size_t oldSize( vEncryptedDataParted.size() );
+               vEncryptedDataParted.resize(oldSize+ulEncryptedPartLen);
+               CK_BYTE dummy;
+               const CK_BYTE_PTR pEncryptedPart( ulEncryptedPartLen>0 ? &vEncryptedDataParted.at(oldSize) : &dummy );
+               CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_EncryptUpdate(hSession,(CK_BYTE_PTR)&(*i),lPartLen,pEncryptedPart,&ulEncryptedPartLen) ) );
+               vEncryptedDataParted.resize(oldSize+ulEncryptedPartLen);
+       }
+       {
+               CK_ULONG ulLastEncryptedPartLen;
+               const CK_RV rv( CRYPTOKI_F_PTR( C_EncryptFinal(hSession,NULL_PTR,&ulLastEncryptedPartLen) ) );
+               if ( isSizeOK ) {
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+                       const size_t oldSize( vEncryptedDataParted.size() );
+                       CK_BYTE dummy;
+                       vEncryptedDataParted.resize(oldSize+ulLastEncryptedPartLen);
+                       const CK_BYTE_PTR pLastEncryptedPart( ulLastEncryptedPartLen>0 ? &vEncryptedDataParted.at(oldSize) : &dummy );
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_EncryptFinal(hSession,pLastEncryptedPart,&ulLastEncryptedPartLen) ) );
+                       vEncryptedDataParted.resize(oldSize+ulLastEncryptedPartLen);
+               } else {
+                       CPPUNIT_ASSERT_EQUAL_MESSAGE("C_EncryptFinal should fail with C_CKR_DATA_LEN_RANGE", (CK_RV)CKR_DATA_LEN_RANGE, rv);
+                       vEncryptedDataParted = vData;
+               }
+       }
+
+       // Single-part decryption
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_DecryptInit(hSession,pMechanism,hKey) ) );
+
+       {
+               CK_ULONG ulDataLen;
+               const CK_RV rv( CRYPTOKI_F_PTR( C_Decrypt(hSession,&vEncryptedData.front(),vEncryptedData.size(),NULL_PTR,&ulDataLen) ) );
+               if ( isSizeOK ) {
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+                       std::vector<CK_BYTE> vDecryptedData(ulDataLen);
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_Decrypt(hSession,&vEncryptedData.front(),vEncryptedData.size(),&vDecryptedData.front(),&ulDataLen) ) );
+                       vDecryptedData.resize(ulDataLen);
+                       CPPUNIT_ASSERT_MESSAGE("C_Encrypt C_Decrypt does not give the original", vData==vDecryptedData);
+               } else {
+                       CPPUNIT_ASSERT_EQUAL_MESSAGE( "C_Decrypt should fail with CKR_ENCRYPTED_DATA_LEN_RANGE", (CK_RV)CKR_ENCRYPTED_DATA_LEN_RANGE, rv );
+               }
+       }
+
+       // Multi-part decryption
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_DecryptInit(hSession,pMechanism,hKey) ) );
+       {
+               std::vector<CK_BYTE> vDecryptedData;
+               CK_BYTE dummy;
+               for ( std::vector<CK_BYTE>::iterator i(vEncryptedDataParted.begin()); i<vEncryptedDataParted.end(); i+=partSize.getCurrent()) {
+                       const CK_ULONG ulPartLen( i+partSize.getNext()<vEncryptedDataParted.end() ? partSize.getCurrent() : vEncryptedDataParted.end()-i );
+                       CK_ULONG ulDecryptedPartLen;
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_DecryptUpdate(hSession,&(*i),ulPartLen,NULL_PTR,&ulDecryptedPartLen) ) );
+                       const size_t oldSize( vDecryptedData.size() );
+                       vDecryptedData.resize(oldSize+ulDecryptedPartLen);
+                       const CK_BYTE_PTR pDecryptedPart( ulDecryptedPartLen>0 ? &vDecryptedData.at(oldSize) : &dummy );
+                       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_DecryptUpdate(hSession,&(*i),ulPartLen,pDecryptedPart,&ulDecryptedPartLen) ) );
+                       vDecryptedData.resize(oldSize+ulDecryptedPartLen);
+               }
+               {
+                       CK_ULONG ulLastPartLen;
+                       const CK_RV rv( CRYPTOKI_F_PTR( C_DecryptFinal(hSession,NULL_PTR,&ulLastPartLen) ) );
+                       if ( isSizeOK ) {
+                               CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+                               const size_t oldSize( vDecryptedData.size() );
+                               vDecryptedData.resize(oldSize+ulLastPartLen);
+                               const CK_BYTE_PTR pLastPart( ulLastPartLen>0 ? &vDecryptedData.at(oldSize) : &dummy );
+                               CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_DecryptFinal(hSession,pLastPart,&ulLastPartLen) ) );
+                               vDecryptedData.resize(oldSize+ulLastPartLen);
+                               CPPUNIT_ASSERT_MESSAGE("C_EncryptUpdate/C_EncryptFinal C_DecryptUpdate/C_DecryptFinal does not give the original", vData==vDecryptedData);
+                       } else {
+                               CPPUNIT_ASSERT_EQUAL_MESSAGE( "C_EncryptFinal should fail with CKR_ENCRYPTED_DATA_LEN_RANGE", (CK_RV)CKR_ENCRYPTED_DATA_LEN_RANGE, rv );
+                       }
+               }
+       }
+}
+
+CK_RV SymmetricAlgorithmTests::generateRsaPrivateKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey)
+{
+       CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
+       CK_ULONG bits = 1536;
+       CK_BYTE pubExp[] = {0x01, 0x00, 0x01};
+       CK_BYTE subject[] = { 0x12, 0x34 }; // dummy
+       CK_BYTE id[] = { 123 } ; // dummy
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE pubAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bFalse, sizeof(bFalse) },
+               { CKA_MODULUS_BITS, &bits, sizeof(bits) },
+               { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) }
+       };
+       CK_ATTRIBUTE privAttribs[] = {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bPrivate, sizeof(bPrivate) },
+               { CKA_SUBJECT, &subject[0], sizeof(subject) },
+               { CKA_ID, &id[0], sizeof(id) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_SIGN, &bTrue, sizeof(bTrue) },
+               { CKA_UNWRAP, &bFalse, sizeof(bFalse) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }
+       };
+
+       CK_OBJECT_HANDLE hPub = CK_INVALID_HANDLE;
+       hKey = CK_INVALID_HANDLE;
+       CK_RV rv;
+       rv = CRYPTOKI_F_PTR( C_GenerateKeyPair(hSession, &mechanism,
+                              pubAttribs, sizeof(pubAttribs)/sizeof(CK_ATTRIBUTE),
+                              privAttribs, sizeof(privAttribs)/sizeof(CK_ATTRIBUTE),
+                              &hPub, &hKey) );
+       if (hPub != CK_INVALID_HANDLE)
+       {
+               CRYPTOKI_F_PTR( C_DestroyObject(hSession, hPub) );
+       }
+       return rv;
+}
+
+void SymmetricAlgorithmTests::aesWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
+{
+       CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
+       CK_KEY_TYPE genKeyType = CKK_GENERIC_SECRET;
+       CK_BYTE keyPtr[128];
+       CK_ULONG keyLen =
+               mechanismType == CKM_AES_KEY_WRAP_PAD ? 125UL : 128UL;
+       CK_ATTRIBUTE attribs[] = {
+               { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) },
+               { CKA_CLASS, &secretClass, sizeof(secretClass) },
+               { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, // Wrapping is allowed even on sensitive objects
+               { CKA_VALUE, keyPtr, keyLen }
+       };
+       CK_OBJECT_HANDLE hSecret;
+       CK_RV rv;
+
+       rv = CRYPTOKI_F_PTR( C_GenerateRandom(hSession, keyPtr, keyLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       hSecret = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hSecret) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hSecret != CK_INVALID_HANDLE);
+
+       CK_BYTE_PTR wrappedPtr = NULL_PTR;
+       CK_ULONG wrappedLen = 0UL;
+       CK_ULONG zero = 0UL;
+       CK_ULONG rndKeyLen = keyLen;
+       if (mechanismType == CKM_AES_KEY_WRAP_PAD)
+               rndKeyLen =  (keyLen + 7) & ~7;
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) );
+       CPPUNIT_ASSERT(rv == CKR_KEY_UNEXTRACTABLE);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hSecret) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       attribs[0].pValue = &bTrue;
+
+       hSecret = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_CreateObject(hSession, attribs, sizeof(attribs)/sizeof(CK_ATTRIBUTE), &hSecret) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hSecret != CK_INVALID_HANDLE);
+
+       // Estimate wrapped length
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(wrappedLen == rndKeyLen + 8);
+
+       wrappedPtr = (CK_BYTE_PTR) malloc(wrappedLen);
+       CPPUNIT_ASSERT(wrappedPtr != NULL_PTR);
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &wrappedLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(wrappedLen == rndKeyLen + 8);
+
+       // This should always fail because wrapped data have to be longer than 0 bytes
+       zero = 0;
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hSecret, wrappedPtr, &zero) );
+       CPPUNIT_ASSERT(rv == CKR_BUFFER_TOO_SMALL);
+
+       CK_ATTRIBUTE nattribs[] = {
+               { CKA_CLASS, &secretClass, sizeof(secretClass) },
+               { CKA_KEY_TYPE, &genKeyType, sizeof(genKeyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bFalse, sizeof(bFalse) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bFalse,sizeof(bFalse) },
+               { CKA_VERIFY, &bTrue, sizeof(bTrue) }
+       };
+       CK_OBJECT_HANDLE hNew;
+
+       hNew = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_UnwrapKey(hSession, &mechanism, hKey, wrappedPtr, wrappedLen, nattribs, sizeof(nattribs)/sizeof(CK_ATTRIBUTE), &hNew) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hNew != CK_INVALID_HANDLE);
+
+       free(wrappedPtr);
+       wrappedPtr = NULL_PTR;
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hSecret) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_OBJECT_HANDLE hRsa;
+       hRsa = CK_INVALID_HANDLE;
+       rv = generateRsaPrivateKey(hSession, CK_TRUE, CK_TRUE, hRsa);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hRsa != CK_INVALID_HANDLE);
+
+       CK_OBJECT_CLASS privateClass = CKO_PRIVATE_KEY;
+       CK_KEY_TYPE rsaKeyType = CKK_RSA;
+       CK_BYTE_PTR p2Ptr = NULL_PTR;
+       CK_ULONG p2Len = 0UL;
+       CK_ATTRIBUTE rsaAttribs[] = {
+               { CKA_CLASS, &privateClass, sizeof(privateClass) },
+               { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) },
+               { CKA_PRIME_2, NULL_PTR, 0UL }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hRsa, rsaAttribs, sizeof(rsaAttribs)/sizeof(CK_ATTRIBUTE)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CPPUNIT_ASSERT(rsaAttribs[0].ulValueLen == sizeof(CK_OBJECT_CLASS));
+       CPPUNIT_ASSERT(*(CK_OBJECT_CLASS*)rsaAttribs[0].pValue == CKO_PRIVATE_KEY);
+       CPPUNIT_ASSERT(rsaAttribs[1].ulValueLen == sizeof(CK_KEY_TYPE));
+       CPPUNIT_ASSERT(*(CK_KEY_TYPE*)rsaAttribs[1].pValue == CKK_RSA);
+
+       p2Len = rsaAttribs[2].ulValueLen;
+       p2Ptr = (CK_BYTE_PTR) malloc(2 * p2Len);
+       CPPUNIT_ASSERT(p2Ptr != NULL_PTR);
+       rsaAttribs[2].pValue = p2Ptr;
+       rsaAttribs[2].ulValueLen = p2Len;
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hRsa, rsaAttribs, sizeof(rsaAttribs)/sizeof(CK_ATTRIBUTE)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(rsaAttribs[2].ulValueLen == p2Len);
+
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hRsa, wrappedPtr, &wrappedLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       wrappedPtr = (CK_BYTE_PTR) malloc(wrappedLen);
+       CPPUNIT_ASSERT(wrappedPtr != NULL_PTR);
+       rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hKey, hRsa, wrappedPtr, &wrappedLen) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hRsa) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_ATTRIBUTE nRsaAttribs[] = {
+               { CKA_CLASS, &privateClass, sizeof(privateClass) },
+               { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) },
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_SIGN, &bFalse,sizeof(bFalse) },
+               { CKA_UNWRAP, &bTrue, sizeof(bTrue) },
+               { CKA_SENSITIVE, &bFalse, sizeof(bFalse) },
+               { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) }
+       };
+
+       hRsa = CK_INVALID_HANDLE;
+       rv = CRYPTOKI_F_PTR( C_UnwrapKey(hSession, &mechanism, hKey, wrappedPtr, wrappedLen, nRsaAttribs, sizeof(nRsaAttribs)/sizeof(CK_ATTRIBUTE), &hRsa) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(hRsa != CK_INVALID_HANDLE);
+
+       rsaAttribs[2].pValue = p2Ptr + p2Len;
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hRsa, rsaAttribs, sizeof(rsaAttribs)/sizeof(CK_ATTRIBUTE)) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CPPUNIT_ASSERT(rsaAttribs[0].ulValueLen == sizeof(CK_OBJECT_CLASS));
+       CPPUNIT_ASSERT(*(CK_OBJECT_CLASS*)rsaAttribs[0].pValue == CKO_PRIVATE_KEY);
+       CPPUNIT_ASSERT(rsaAttribs[1].ulValueLen == sizeof(CK_KEY_TYPE));
+       CPPUNIT_ASSERT(*(CK_KEY_TYPE*)rsaAttribs[1].pValue == CKK_RSA);
+       CPPUNIT_ASSERT(rsaAttribs[2].ulValueLen == p2Len);
+       CPPUNIT_ASSERT(memcmp(p2Ptr, p2Ptr + p2Len, p2Len) == 0);
+
+       free(wrappedPtr);
+       free(p2Ptr);
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hRsa) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void SymmetricAlgorithmTests::testAesEncryptDecrypt()
+{
+       CK_RV rv;
+       // CK_UTF8CHAR sopin[] = SLOT_0_SO1_PIN;
+       // CK_ULONG sopinLength = sizeof(sopin) - 1;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token keys.
+       rv = generateAesKey(hSessionRW,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // AES allways have the block size of 128 bits (0x80 bits 0x10 bytes).
+       // with padding all message sizes could be encrypted-decrypted.
+       // without padding the message size must be a multiple of the block size.
+       const int blockSize(0x10);
+       encryptDecrypt(CKM_AES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_AES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_AES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_AES_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_AES_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+       encryptDecrypt(CKM_AES_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_AES_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+       encryptDecrypt(CKM_AES_CTR,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_AES_CTR,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_AES_CTR,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+#ifdef WITH_AES_GCM
+       encryptDecrypt(CKM_AES_GCM,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_AES_GCM,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_AES_GCM,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+#endif
+}
+
+void SymmetricAlgorithmTests::testAesWrapUnwrap()
+{
+       CK_RV rv;
+       // CK_UTF8CHAR sopin[] = SLOT_0_SO1_PIN;
+       // CK_ULONG sopinLength = sizeof(sopin) - 1;
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the session so we can create a private object
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Generate a wrapping session public key
+       rv = generateAesKey(hSession,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       aesWrapUnwrap(CKM_AES_KEY_WRAP, hSession, hKey);
+#ifdef HAVE_AES_KEY_WRAP_PAD
+       aesWrapUnwrap(CKM_AES_KEY_WRAP_PAD, hSession, hKey);
+#endif
+}
+
+void SymmetricAlgorithmTests::testDesEncryptDecrypt()
+{
+       CK_RV rv;
+       // CK_UTF8CHAR sopin[] = SLOT_0_SO1_PIN;
+       // CK_ULONG sopinLength = sizeof(sopin) - 1;
+       CK_SESSION_HANDLE hSessionRO;
+       CK_SESSION_HANDLE hSessionRW;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Open read-only session on when the token is not initialized should fail
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-only session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSessionRO) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSessionRW) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSessionRO,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       // 3DES and DES always have the block size of 64 bits (0x40 bits 0x8 bytes).
+       // with padding all message sizes could be encrypted-decrypted.
+       // without padding the message size must be a multiple of the block size.
+       const int blockSize(0x8);
+
+#ifndef WITH_FIPS
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token keys.
+       rv = generateDesKey(hSessionRW,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       encryptDecrypt(CKM_DES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_DES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_DES_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+       encryptDecrypt(CKM_DES_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+
+       CK_OBJECT_HANDLE hKey2 = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token keys.
+       rv = generateDes2Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKey2);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+       encryptDecrypt(CKM_DES3_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+#endif
+
+       CK_OBJECT_HANDLE hKey3 = CK_INVALID_HANDLE;
+
+       // Generate all combinations of session/token keys.
+       rv = generateDes3Key(hSessionRW,IN_SESSION,IS_PUBLIC,hKey3);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST-1);
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1);
+       encryptDecrypt(CKM_DES3_CBC_PAD,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_CBC,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+       encryptDecrypt(CKM_DES3_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST);
+       encryptDecrypt(CKM_DES3_ECB,blockSize,hSessionRO,hKey,blockSize*NR_OF_BLOCKS_IN_TEST+1, false);
+}
+
+void SymmetricAlgorithmTests::testNullTemplate()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_MECHANISM mechanism1 = { CKM_DES3_KEY_GEN, NULL_PTR, 0 };
+       CK_MECHANISM mechanism2 = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism1, NULL_PTR, 0, &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism2, NULL_PTR, 0, &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_TEMPLATE_INCOMPLETE);
+}
+
+void SymmetricAlgorithmTests::testNonModifiableDesKeyGeneration()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_MECHANISM mechanism = { CKM_DES3_KEY_GEN, NULL_PTR, 0 };
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_BBOOL bToken = IN_SESSION;
+
+       CK_ATTRIBUTE keyAttribs[] =
+               {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_MODIFIABLE, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bTrue, sizeof(bTrue) }
+       };
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+               keyAttribs, sizeof(keyAttribs)/sizeof(CK_ATTRIBUTE),
+               &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // The C_GenerateKey call failed if CKA_MODIFIABLE was bFalse
+       // This was a bug in the SoftHSM implementation
+       keyAttribs[2].pValue = &bFalse;
+       keyAttribs[2].ulValueLen = sizeof(bFalse);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+               keyAttribs, sizeof(keyAttribs) / sizeof(CK_ATTRIBUTE),
+               &hKey) );
+       // The call would fail with CKR_ATTRIBUTE_READ_ONLY
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Now create a template where the CKA_MODIFIABLE attribute is last in the list
+       CK_ATTRIBUTE keyAttribs1[] =
+       {
+               { CKA_TOKEN, &bToken, sizeof(bToken) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bTrue, sizeof(bTrue) },
+               { CKA_MODIFIABLE, &bTrue, sizeof(bTrue) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+               keyAttribs1, sizeof(keyAttribs1) / sizeof(CK_ATTRIBUTE),
+               &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Now when CKA_MODIFIABLE is bFalse the key generation succeeds
+       keyAttribs1[2].pValue = &bFalse;
+       keyAttribs1[2].ulValueLen = sizeof(bFalse);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+               keyAttribs1, sizeof(keyAttribs1) / sizeof(CK_ATTRIBUTE),
+               &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void SymmetricAlgorithmTests::testCheckValue()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+       CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the sessions so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_ULONG bytes = 16;
+       CK_BYTE pCheckValue[] = { 0x2b, 0x84, 0xf6 };
+       CK_BBOOL bFalse = CK_FALSE;
+       CK_BBOOL bTrue = CK_TRUE;
+       CK_ATTRIBUTE keyAttribs[] = {
+               { CKA_TOKEN, &bFalse, sizeof(bFalse) },
+               { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+               { CKA_ENCRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_DECRYPT, &bTrue, sizeof(bTrue) },
+               { CKA_WRAP, &bTrue, sizeof(bTrue) },
+               { CKA_UNWRAP, &bTrue, sizeof(bTrue) },
+               { CKA_VALUE_LEN, &bytes, sizeof(bytes) },
+               { CKA_CHECK_VALUE, &pCheckValue, sizeof(pCheckValue) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                          keyAttribs, 8,
+                          &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_ATTRIBUTE_VALUE_INVALID);
+
+       keyAttribs[7].ulValueLen = 0;
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                          keyAttribs, 8,
+                          &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_ATTRIBUTE checkAttrib[] = {
+               { CKA_CHECK_VALUE, &pCheckValue, sizeof(pCheckValue) }
+       };
+
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hKey, checkAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(checkAttrib[0].ulValueLen == 0);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_GenerateKey(hSession, &mechanism,
+                          keyAttribs, 7,
+                          &hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       checkAttrib[0].ulValueLen = sizeof(pCheckValue);
+       rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hKey, checkAttrib, 1) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(checkAttrib[0].ulValueLen == 3);
+
+       rv = CRYPTOKI_F_PTR( C_DestroyObject(hSession, hKey) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void SymmetricAlgorithmTests::testAesCtrOverflow()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Initialize the library and start the test.
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Open read-write session
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Login USER into the session so we can create a private objects
+       rv = CRYPTOKI_F_PTR( C_Login(hSession,CKU_USER,m_userPin1,m_userPin1Length) );
+       CPPUNIT_ASSERT(rv==CKR_OK);
+
+       CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+
+       // Generate a session keys.
+       rv = generateAesKey(hSession,IN_SESSION,IS_PUBLIC,hKey);
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       CK_MECHANISM mechanism = { CKM_AES_CTR, NULL_PTR, 0 };
+       CK_AES_CTR_PARAMS ctrParams =
+       {
+               2,
+               {
+                       0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+               }
+       };
+       mechanism.pParameter = &ctrParams;
+       mechanism.ulParameterLen = sizeof(ctrParams);
+
+       CK_BYTE plainText[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+                               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+                               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+                               0x00 };
+       std::vector<CK_BYTE> vEncryptedData;
+       std::vector<CK_BYTE> vEncryptedDataParted;
+       std::vector<CK_BYTE> vDecryptedData;
+       std::vector<CK_BYTE> vDecryptedDataParted;
+       CK_ULONG ulEncryptedDataLen;
+       CK_ULONG ulEncryptedPartLen;
+       CK_ULONG ulDataLen;
+       CK_ULONG ulDataPartLen;
+
+       // Single-part encryption
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,plainText,sizeof(plainText),NULL_PTR,&ulEncryptedDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_DATA_LEN_RANGE, rv );
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,plainText,sizeof(plainText)-1,NULL_PTR,&ulEncryptedDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vEncryptedData.resize(ulEncryptedDataLen);
+       rv = CRYPTOKI_F_PTR( C_Encrypt(hSession,plainText,sizeof(plainText)-1,&vEncryptedData.front(),&ulEncryptedDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vEncryptedData.resize(ulEncryptedDataLen);
+
+       // Multi-part encryption
+       rv = CRYPTOKI_F_PTR( C_EncryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_EncryptUpdate(hSession,plainText,sizeof(plainText)-1,NULL_PTR,&ulEncryptedPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vEncryptedDataParted.resize(ulEncryptedPartLen);
+       rv = CRYPTOKI_F_PTR( C_EncryptUpdate(hSession,plainText,sizeof(plainText)-1,&vEncryptedDataParted.front(),&ulEncryptedPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vEncryptedDataParted.resize(ulEncryptedPartLen);
+       rv = CRYPTOKI_F_PTR( C_EncryptUpdate(hSession,plainText,1,NULL_PTR,&ulEncryptedPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_DATA_LEN_RANGE, rv );
+
+       // Single-part decryption
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,&vEncryptedData.front(),vEncryptedData.size()+1,NULL_PTR,&ulDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_ENCRYPTED_DATA_LEN_RANGE, rv );
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,&vEncryptedData.front(),vEncryptedData.size(),NULL_PTR,&ulDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vDecryptedData.resize(ulDataLen);
+       rv = CRYPTOKI_F_PTR( C_Decrypt(hSession,&vEncryptedData.front(),vEncryptedData.size(),&vDecryptedData.front(),&ulDataLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vDecryptedData.resize(ulDataLen);
+
+       // Multi-part decryption
+       rv = CRYPTOKI_F_PTR( C_DecryptInit(hSession,&mechanism,hKey) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       rv = CRYPTOKI_F_PTR( C_DecryptUpdate(hSession,&vEncryptedData.front(),vEncryptedData.size(),NULL_PTR,&ulDataPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vDecryptedDataParted.resize(ulDataPartLen);
+       rv = CRYPTOKI_F_PTR( C_DecryptUpdate(hSession,&vEncryptedData.front(),vEncryptedData.size(),&vDecryptedDataParted.front(),&ulDataPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, rv );
+       vDecryptedDataParted.resize(ulDataPartLen);
+       rv = CRYPTOKI_F_PTR( C_DecryptUpdate(hSession,&vEncryptedData.front(),1,NULL_PTR,&ulDataPartLen) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_ENCRYPTED_DATA_LEN_RANGE, rv );
+}
diff --git a/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h b/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h
new file mode 100644 (file)
index 0000000..9b96ae1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012 SURFnet
+ * 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.
+ */
+
+/*****************************************************************************
+ SymmetricAlgorithmTests.h
+
+ Contains test cases for symmetrical algorithms (i.e., AES and DES)
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SYMENCRYPTDECRYPTTESTS_H
+#define _SOFTHSM_V2_SYMENCRYPTDECRYPTTESTS_H
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class SymmetricAlgorithmTests : public TestsBase
+{
+       CPPUNIT_TEST_SUITE(SymmetricAlgorithmTests);
+       CPPUNIT_TEST(testAesEncryptDecrypt);
+       CPPUNIT_TEST(testDesEncryptDecrypt);
+#ifdef HAVE_AES_KEY_WRAP
+       CPPUNIT_TEST(testAesWrapUnwrap);
+#endif
+       CPPUNIT_TEST(testNullTemplate);
+       CPPUNIT_TEST(testNonModifiableDesKeyGeneration);
+       CPPUNIT_TEST(testCheckValue);
+       CPPUNIT_TEST(testAesCtrOverflow);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testAesEncryptDecrypt();
+       void testDesEncryptDecrypt();
+       void testAesWrapUnwrap();
+       void testNullTemplate();
+       void testNonModifiableDesKeyGeneration();
+       void testCheckValue();
+       void testAesCtrOverflow();
+
+protected:
+       CK_RV generateAesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+#ifndef WITH_FIPS
+       CK_RV generateDesKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       CK_RV generateDes2Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+#endif
+       CK_RV generateDes3Key(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+       void encryptDecrypt(
+                       CK_MECHANISM_TYPE mechanismType,
+                       size_t sizeOfIV,
+                       CK_SESSION_HANDLE hSession,
+                       CK_OBJECT_HANDLE hKey,
+                       size_t messageSize,
+                       bool isSizeOK=true);
+       void aesWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey);
+       CK_RV generateRsaPrivateKey(CK_SESSION_HANDLE hSession, CK_BBOOL bToken, CK_BBOOL bPrivate, CK_OBJECT_HANDLE &hKey);
+};
+
+#endif // !_SOFTHSM_V2_SYMENCRYPTDECRYPTTESTS_H
diff --git a/SoftHSMv2/src/lib/test/TestsBase.cpp b/SoftHSMv2/src/lib/test/TestsBase.cpp
new file mode 100644 (file)
index 0000000..1c8467c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TestsBase.cpp
+
+ Base class for test classes.
+ *****************************************************************************/
+
+#include "TestsBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+void TestsBase::setUp() {
+       TestsNoPINInitBase::setUp();
+
+       CK_SESSION_HANDLE hSession;
+
+       // Open session
+       CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION|CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession)==CKR_OK ) );
+
+       // Login SO
+       CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_Login(hSession,CKU_SO, m_soPin1, m_soPin1Length)==CKR_OK ) );
+
+       // Initialize the user pin
+       CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, m_userPin1Length)==CKR_OK ) );
+}
diff --git a/SoftHSMv2/src/lib/test/TestsBase.h b/SoftHSMv2/src/lib/test/TestsBase.h
new file mode 100644 (file)
index 0000000..6bcf894
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TestsBase.h
+
+ Base class for test classes.
+ *****************************************************************************/
+
+#ifndef SRC_LIB_TEST_TESTSBASE_H_
+#define SRC_LIB_TEST_TESTSBASE_H_
+
+#include <TestsNoPINInitBase.h>
+
+class TestsBase : public TestsNoPINInitBase {
+public:
+       virtual void setUp();
+};
+
+
+#endif /* SRC_LIB_TEST_TESTSBASE_H_ */
diff --git a/SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp b/SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp
new file mode 100644 (file)
index 0000000..f5bb066
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TestsNoPINInitBase.cpp
+
+ Base class for test classes. Used when there is no need for user login.
+ *****************************************************************************/
+
+#include "TestsNoPINInitBase.h"
+#include <cstring>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vector>
+#include <sstream>
+
+#ifdef P11M
+#ifdef _WIN32
+CK_FUNCTION_LIST_PTR FunctionList::getFunctionListPtr(const char*const libName,  HINSTANCE__* p11Library, const char*getFunctionList) {
+#else
+#include <dlfcn.h>
+
+static CK_FUNCTION_LIST_PTR getFunctionListPtr(const char*const libName, void *const p11Library, const char*getFunctionList) {
+#endif //_WIN32
+       CPPUNIT_ASSERT_MESSAGE(libName, p11Library);
+#ifdef _WIN32
+       const CK_C_GetFunctionList pGFL( (CK_C_GetFunctionList)GetProcAddress(
+                       p11Library,
+                       getFunctionList.c_str()
+       ) );
+#else
+       const CK_C_GetFunctionList pGFL( (CK_C_GetFunctionList)dlsym(
+                       p11Library,
+                       getFunctionList
+       ) );
+#endif //_WIN32
+       CPPUNIT_ASSERT_MESSAGE(libName, pGFL);
+       CK_FUNCTION_LIST_PTR ptr(NULL_PTR);
+       const CK_RV retCode( pGFL(&ptr) );
+       if ( !ptr && (retCode)!=CKR_OK) {
+               std::ostringstream oss;
+               oss << "C_GetFunctionList failed...error no = 0x" << std::hex << retCode << " libName '" << libName << "'.";
+               CPPUNIT_ASSERT_MESSAGE(oss.str(), false);
+       }
+       return ptr;
+}
+#endif //P11M
+void TestsNoPINInitBase::getSlotIDs() {
+       bool hasFoundFree(false);
+       bool hasFoundInitialized(false);
+       CK_ULONG nrOfSlots;
+       CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, NULL_PTR, &nrOfSlots)==CKR_OK ) );
+       std::vector<CK_SLOT_ID> slotIDs(nrOfSlots);
+       CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, &slotIDs.front(), &nrOfSlots)==CKR_OK ) );
+       for ( std::vector<CK_SLOT_ID>::iterator i=slotIDs.begin(); i!=slotIDs.end(); i++ ) {
+               CK_TOKEN_INFO tokenInfo;
+               CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_GetTokenInfo(*i, &tokenInfo)==CKR_OK ) );
+               if ( tokenInfo.flags&CKF_TOKEN_INITIALIZED ) {
+                       if ( !hasFoundInitialized ) {
+                               hasFoundInitialized = true;
+                               m_initializedTokenSlotID = *i;
+                       }
+               } else {
+                       if ( !hasFoundFree ) {
+                               hasFoundFree = true;
+                               m_notInitializedTokenSlotID = *i;
+                       }
+               }
+       }
+       if ( !hasFoundInitialized ) {
+               m_initializedTokenSlotID = m_notInitializedTokenSlotID;
+       }
+}
+
+TestsNoPINInitBase::TestsNoPINInitBase() :
+#ifdef P11M
+#ifdef _WIN32
+               p11Library( LoadLibrary(libName.c_str()) ),
+#else
+               p11Library( dlopen(P11M, RTLD_LAZY) ),
+#endif
+               m_ptr(getFunctionListPtr(P11M, p11Library, "C_GetFunctionList")),
+#endif
+               m_invalidSlotID(((CK_SLOT_ID)1<<31)),
+               m_initializedTokenSlotID(m_invalidSlotID),
+               m_notInitializedTokenSlotID(m_invalidSlotID),
+               m_soPin1((CK_UTF8CHAR_PTR)"12345678"),
+               m_soPin1Length(strlen((char*)m_soPin1)),
+               m_userPin1((CK_UTF8CHAR_PTR)"1234"),
+               m_userPin1Length(strlen((char*)m_userPin1)) {};
+
+void TestsNoPINInitBase::setUp() {
+       CK_UTF8CHAR label[32];
+       memset(label, ' ', 32);
+       memcpy(label, "token1", strlen("token1"));
+
+       // initialize cryptoki
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) ) );
+       // update slot IDs to initialized and not initialized token.
+       getSlotIDs();
+       // (Re)initialize the token
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) ) );
+       // Reset cryptoki to get new slot IDs.
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) ) );
+       CPPUNIT_ASSERT_EQUAL( (CK_RV)CKR_OK, CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) ) );
+       // slot IDs must be updated since the ID of the initialized token has changed.
+       getSlotIDs();
+}
+
+void TestsNoPINInitBase::tearDown() {
+       const CK_RV result(CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) ) );
+       if ( result==CKR_OK||result==CKR_CRYPTOKI_NOT_INITIALIZED ) {
+               return;
+       }
+       std::ostringstream oss;
+       oss << "C_Finalize failed with CK_RV: " << std::hex << result;
+       CPPUNIT_ASSERT_MESSAGE(oss.str(), false);
+}
+
+#ifdef P11M
+TestsNoPINInitBase::~TestsNoPINInitBase() {
+       if ( !p11Library ) {
+               return;
+       }
+#ifdef _WIN32
+       FreeLibrary(p11Library);
+#else
+       dlclose(p11Library);
+#endif // _WIN32
+}
+
+void softHSMLog(const int, const char*, const char*, const int, const char*, ...)
+{
+
+}
+#else
+TestsNoPINInitBase::~TestsNoPINInitBase() {}
+#endif // P11M
diff --git a/SoftHSMv2/src/lib/test/TestsNoPINInitBase.h b/SoftHSMv2/src/lib/test/TestsNoPINInitBase.h
new file mode 100644 (file)
index 0000000..acce9f1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TestsNoPINInitBase.h
+
+ Base class for test classes. Used when there is no need for user login.
+ *****************************************************************************/
+
+#ifndef SRC_LIB_TEST_TESTSNOPININITBASE_H_
+#define SRC_LIB_TEST_TESTSNOPININITBASE_H_
+
+#include "cryptoki.h"
+#include <cppunit/TestFixture.h>
+
+
+#ifdef P11M
+#define CRYPTOKI_F_PTR(func) m_ptr->func
+#else
+#define CRYPTOKI_F_PTR(func) func
+#endif
+
+class TestsNoPINInitBase : public CppUnit::TestFixture {
+public:
+       TestsNoPINInitBase();
+       virtual ~TestsNoPINInitBase();
+
+       virtual void setUp();
+       virtual void tearDown();
+private:
+       void getSlotIDs();
+#ifdef P11M
+#ifdef _WIN32
+       HINSTANCE__* p11Library;
+#else
+       void *const p11Library;
+#endif
+protected:
+       const CK_FUNCTION_LIST_PTR m_ptr;
+#else
+protected:
+#endif
+       const CK_SLOT_ID m_invalidSlotID;
+       CK_SLOT_ID m_initializedTokenSlotID;
+       CK_SLOT_ID m_notInitializedTokenSlotID;
+
+       const CK_UTF8CHAR_PTR m_soPin1;
+       const CK_ULONG m_soPin1Length;
+
+       const CK_UTF8CHAR_PTR m_userPin1;
+       const CK_ULONG m_userPin1Length;
+};
+
+
+#endif /* SRC_LIB_TEST_TESTSNOPININITBASE_H_ */
diff --git a/SoftHSMv2/src/lib/test/TokenTests.cpp b/SoftHSMv2/src/lib/test/TokenTests.cpp
new file mode 100644 (file)
index 0000000..9fc77ba
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TokenTests.cpp
+
+ Contains test cases to C_InitToken
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "TokenTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TokenTests);
+
+void TokenTests::testInitToken()
+{
+       CK_RV rv;
+       CK_UTF8CHAR label[32];
+       CK_SESSION_HANDLE hSession;
+       CK_TOKEN_INFO tokenInfo;
+       CK_CHAR serialNumber[16];
+
+       memset(label, ' ', 32);
+       memcpy(label, "token1", strlen("token1"));
+
+       // Just make sure that we finalize any previous failed tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, NULL_PTR, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_invalidSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID);
+
+       // Initialize
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Get token serial
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_initializedTokenSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       memcpy(serialNumber, tokenInfo.serialNumber, 16);
+
+       // Initialize with wrong password
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length - 1, label) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_EXISTS);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Re-initialize
+       rv = CRYPTOKI_F_PTR( C_InitToken(m_initializedTokenSlotID, m_soPin1, m_soPin1Length, label) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       // Compare token serial
+       rv = CRYPTOKI_F_PTR( C_GetTokenInfo(m_initializedTokenSlotID, &tokenInfo) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CPPUNIT_ASSERT(memcmp(serialNumber, tokenInfo.serialNumber, 16) == 0);
+
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+}
diff --git a/SoftHSMv2/src/lib/test/TokenTests.h b/SoftHSMv2/src/lib/test/TokenTests.h
new file mode 100644 (file)
index 0000000..cc08b72
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ TokenTests.h
+
+ Contains test cases to C_InitToken
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_TOKENTESTS_H
+#define _SOFTHSM_V2_TOKENTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class TokenTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(TokenTests);
+       CPPUNIT_TEST(testInitToken);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testInitToken();
+};
+
+#endif // !_SOFTHSM_V2_TOKENTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/UserTests.cpp b/SoftHSMv2/src/lib/test/UserTests.cpp
new file mode 100644 (file)
index 0000000..d4999e5
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ UserTests.cpp
+
+ Contains test cases to C_InitPIN, C_SetPIN, C_Login, and C_Logout
+ *****************************************************************************/
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include "UserTests.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(UserTests);
+
+void UserTests::testInitPIN()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_NOT_LOGGED_IN);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_InitPIN(CK_INVALID_HANDLE, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, 0) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_LEN_RANGE);
+
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void UserTests::testLogin()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession[2];
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Set up user PIN
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession[0]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_PIN_NOT_INITIALIZED);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession[0], m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession[0]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(CK_INVALID_HANDLE, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, NULL_PTR, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, 0) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession[1]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY_EXISTS);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession[1]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession[0]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_ALREADY_LOGGED_IN);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession[0]) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length - 1) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession[0], CKU_USER, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_ALREADY_LOGGED_IN);
+}
+
+void UserTests::testLogout()
+{
+       CK_RV rv;
+       CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(CK_INVALID_HANDLE) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
+
+void UserTests::testSetPIN()
+{
+       CK_RV rv;
+       const CK_UTF8CHAR_PTR pin2((CK_UTF8CHAR_PTR)"12345");
+       const CK_ULONG pin2Length(strlen((char*)pin2));
+       const CK_UTF8CHAR_PTR so2pin((CK_UTF8CHAR_PTR)"123456789");
+       const CK_ULONG so2pinLength(strlen((char*)so2pin));
+       CK_SESSION_HANDLE hSession;
+
+       // Just make sure that we finalize any previous tests
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       // Set up user PIN
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       rv = CRYPTOKI_F_PTR( C_InitPIN(hSession, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+       CRYPTOKI_F_PTR( C_Finalize(NULL_PTR) );
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       rv = CRYPTOKI_F_PTR( C_Initialize(NULL_PTR) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(CK_INVALID_HANDLE, m_userPin1, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_SESSION_READ_ONLY);
+
+       rv = CRYPTOKI_F_PTR( C_CloseSession(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_OpenSession(m_initializedTokenSlotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, NULL_PTR, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, NULL_PTR, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, pin2, 0) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_LEN_RANGE);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, pin2, pin2Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_USER, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_userPin1, m_userPin1Length, pin2, pin2Length) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, pin2, pin2Length, m_userPin1, m_userPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
+
+       rv = CRYPTOKI_F_PTR( C_Logout(hSession) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_Login(hSession, CKU_SO, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, so2pin, so2pinLength, so2pin, so2pinLength) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_soPin1, m_soPin1Length, so2pin, so2pinLength) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, m_soPin1, m_soPin1Length, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_PIN_INCORRECT);
+
+       rv = CRYPTOKI_F_PTR( C_SetPIN(hSession, so2pin, so2pinLength, m_soPin1, m_soPin1Length) );
+       CPPUNIT_ASSERT(rv == CKR_OK);
+}
diff --git a/SoftHSMv2/src/lib/test/UserTests.h b/SoftHSMv2/src/lib/test/UserTests.h
new file mode 100644 (file)
index 0000000..9104208
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * 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.
+ */
+
+/*****************************************************************************
+ UserTests.h
+
+ Contains test cases to C_InitPIN, C_SetPIN, C_Login, and C_Logout
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_USERTESTS_H
+#define _SOFTHSM_V2_USERTESTS_H
+
+#include "TestsNoPINInitBase.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class UserTests : public TestsNoPINInitBase
+{
+       CPPUNIT_TEST_SUITE(UserTests);
+       CPPUNIT_TEST(testInitPIN);
+       CPPUNIT_TEST(testLogin);
+       CPPUNIT_TEST(testLogout);
+       CPPUNIT_TEST(testSetPIN);
+       CPPUNIT_TEST_SUITE_END();
+
+public:
+       void testInitPIN();
+       void testLogin();
+       void testLogout();
+       void testSetPIN();
+};
+
+#endif // !_SOFTHSM_V2_USERTESTS_H
+
diff --git a/SoftHSMv2/src/lib/test/p11test.cpp b/SoftHSMv2/src/lib/test/p11test.cpp
new file mode 100644 (file)
index 0000000..1198c91
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ p11test.cpp
+
+ The main test executor for tests on the PKCS#11 interface in SoftHSM v2
+ *****************************************************************************/
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Message.h>
+#include <cppunit/Exception.h>
+#include <cppunit/XmlOutputter.h>
+#include <fstream>
+#include <stdlib.h>
+#include <iostream>
+#ifdef _WIN32
+#include "setenv.h"
+#endif
+
+class MyListener : public CPPUNIT_NS::TestListener {
+       virtual void startTest( CPPUNIT_NS::Test*const pTest ) {
+               std::cout << std::endl << pTest->getName() << ' ' << pTest->countTestCases() << std::endl << std::endl;
+       }
+       virtual void addFailure( const CPPUNIT_NS::TestFailure & failure ) {
+               const CPPUNIT_NS::SourceLine solurceLine( failure.sourceLine() );
+               CPPUNIT_NS::Message message( failure.thrownException()->message() );
+               std::cout << solurceLine.fileName() << ' ' << solurceLine.lineNumber() << ' ' << message.shortDescription() << std::endl;
+               std::cout << message.details() << std::endl << std::endl;
+       }
+};
+int main(int argc, char**const argv)
+{
+#ifndef _WIN32
+       setenv("SOFTHSM2_CONF", "./softhsm2.conf", 1);
+#else
+       setenv("SOFTHSM2_CONF", ".\\softhsm2.conf", 1);
+#endif
+
+       CPPUNIT_NS::TestFactoryRegistry &registry( CPPUNIT_NS::TestFactoryRegistry::getRegistry() );
+
+       CPPUNIT_NS::TextTestRunner runner;
+       runner.addTest(registry.makeTest());
+       if ( argc<2 ) {
+               return runner.run() ? 0 : 1;
+       }
+       if ( std::string("direct").find(*(argv+1))==std::string::npos ) {
+               return runner.run(*(argv+1)) ? 0 : 1;
+       }
+       runner.addTest(registry.makeTest());
+       CPPUNIT_NS::TestResult controller;
+       CPPUNIT_NS::TestResultCollector result;
+       controller.addListener( &result );
+       MyListener progress;
+       controller.addListener( &progress );
+
+       runner.run(controller);
+
+       std::ofstream xmlFileOut("test-results.xml");
+       CppUnit::XmlOutputter xmlOut(&result, xmlFileOut);
+       xmlOut.write();
+
+       return result.wasSuccessful() ? 0 : 1;
+}
diff --git a/SoftHSMv2/src/lib/test/softhsm2-alt.conf.in b/SoftHSMv2/src/lib/test/softhsm2-alt.conf.in
new file mode 100644 (file)
index 0000000..5bdcb1f
--- /dev/null
@@ -0,0 +1,6 @@
+# SoftHSM v2 configuration file
+
+directories.tokendir = @builddir@/tokens
+objectstore.backend = file
+log.level = INFO
+slots.removable = true
diff --git a/SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32 b/SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32
new file mode 100644 (file)
index 0000000..68cb2ec
--- /dev/null
@@ -0,0 +1,6 @@
+# SoftHSM v2 configuration file
+
+directories.tokendir = .\tokens
+objectstore.backend = file
+log.level = INFO
+slots.removable = true
diff --git a/SoftHSMv2/src/lib/test/softhsm2.conf.in b/SoftHSMv2/src/lib/test/softhsm2.conf.in
new file mode 100644 (file)
index 0000000..6554669
--- /dev/null
@@ -0,0 +1,6 @@
+# SoftHSM v2 configuration file
+
+directories.tokendir = @builddir@/tokens
+objectstore.backend = file
+log.level = INFO
+slots.removable = false
diff --git a/SoftHSMv2/src/lib/test/softhsm2.conf.win32 b/SoftHSMv2/src/lib/test/softhsm2.conf.win32
new file mode 100644 (file)
index 0000000..a877d1f
--- /dev/null
@@ -0,0 +1,6 @@
+# SoftHSM v2 configuration file
+
+directories.tokendir = .\tokens
+objectstore.backend = file
+log.level = INFO
+slots.removable = false
diff --git a/SoftHSMv2/src/lib/test/tokens/dummy.in b/SoftHSMv2/src/lib/test/tokens/dummy.in
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/SoftHSMv2/src/lib/win32/dllmain.cc b/SoftHSMv2/src/lib/win32/dllmain.cc
new file mode 100644 (file)
index 0000000..359227d
--- /dev/null
@@ -0,0 +1,18 @@
+#include <windows.h>
+
+__declspec(dllexport) BOOL WINAPI
+DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpvReserved)
+{
+    hModule = hModule;
+    lpvReserved = lpvReserved;
+    
+    switch (ul_reason_for_call) { 
+    case DLL_PROCESS_ATTACH:
+    case DLL_THREAD_ATTACH: 
+    case DLL_THREAD_DETACH: 
+    case DLL_PROCESS_DETACH: 
+    default:
+        break;
+    }
+    return (TRUE);
+}
diff --git a/SoftHSMv2/src/lib/win32/setenv.cpp b/SoftHSMv2/src/lib/win32/setenv.cpp
new file mode 100644 (file)
index 0000000..da41a62
--- /dev/null
@@ -0,0 +1,20 @@
+#include <config.h>
+#include <stdlib.h>
+#include <string>
+
+#ifdef _WIN32
+
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+       std::string vv = name;
+       vv += "=";
+       vv += value;
+
+       if (overwrite != 1)
+               return false;
+
+       return _putenv(vv.c_str()) == 0;
+}
+
+#endif
diff --git a/SoftHSMv2/src/lib/win32/setenv.h b/SoftHSMv2/src/lib/win32/setenv.h
new file mode 100644 (file)
index 0000000..e199227
--- /dev/null
@@ -0,0 +1,12 @@
+#include <config.h>
+
+#ifdef _WIN32
+
+#ifndef _SETENV_H
+#define _SETENV_H
+
+int setenv(const char *name, const char *value, int overwrite);
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/SoftHSMv2/src/lib/win32/syslog.cpp b/SoftHSMv2/src/lib/win32/syslog.cpp
new file mode 100644 (file)
index 0000000..927592e
--- /dev/null
@@ -0,0 +1,69 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#ifdef _WIN32
+
+static HANDLE hEventLog = NULL;
+
+/*
+ * Close the Handle to the application Event Log
+ */
+void
+closelog() {
+       DeregisterEventSource(hEventLog);
+}
+
+/*
+ * Initialize event logging
+ */
+void
+openlog(const char *ident, int logopt, int facility) {
+       /* Get a handle to the Application event log */
+       hEventLog = RegisterEventSourceA(NULL, ident);
+}
+
+/*
+ * Log to the NT Event Log
+ */
+void
+syslog(int priority, const char *message, ...) {
+       va_list ap;
+       char buf[1024];
+       LPCSTR str[1];
+
+       str[0] = buf;
+
+       va_start(ap, message);
+       vsprintf(buf, message, ap);
+       va_end(ap);
+
+       /* Make sure that the channel is open to write the event */
+       if (hEventLog == NULL) {
+               openlog("SoftHSM", 0, 0);
+       }
+       if (hEventLog != NULL) {
+               switch (priority) {
+               case LOG_INFO:
+               case LOG_NOTICE:
+               case LOG_DEBUG:
+                       ReportEventA(hEventLog, EVENTLOG_INFORMATION_TYPE, 0,
+                                    0x40000003, NULL, 1, 0, str, NULL);
+                       break;
+               case LOG_WARNING:
+                       ReportEventA(hEventLog, EVENTLOG_WARNING_TYPE, 0,
+                                    0x80000002, NULL, 1, 0, str, NULL);
+                       break;
+               default:
+                       ReportEventA(hEventLog, EVENTLOG_ERROR_TYPE, 0,
+                                    0xc0000001, NULL, 1, 0, str, NULL);
+                       break;
+               }
+       }
+}
+
+#endif
diff --git a/SoftHSMv2/src/lib/win32/syslog.h b/SoftHSMv2/src/lib/win32/syslog.h
new file mode 100644 (file)
index 0000000..1ed207c
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+
+/* priorities */
+#define LOG_EMERG       0       /* system is unusable */
+#define LOG_ALERT       1       /* action must be taken immediately */
+#define LOG_CRIT        2       /* critical conditions */
+#define LOG_ERR         3       /* error conditions */
+#define LOG_WARNING     4       /* warning conditions */
+#define LOG_NOTICE      5       /* normal but signification condition */
+#define LOG_INFO        6       /* informational */
+#define LOG_DEBUG       7       /* debug-level messages */
+
+/* NT event log does not support facility level */
+#define LOG_KERN       0
+#define LOG_USER       0
+#define LOG_MAIL       0
+#define LOG_DAEMON     0
+#define LOG_AUTH       0
+#define LOG_SYSLOG     0
+#define LOG_LPR                0
+#define LOG_LOCAL0     0
+#define LOG_LOCAL1     0
+#define LOG_LOCAL2     0
+#define LOG_LOCAL3     0
+#define LOG_LOCAL4     0
+#define LOG_LOCAL5     0
+#define LOG_LOCAL6     0
+#define LOG_LOCAL7     0
+
+/* Constant definitions for openlog() */
+#define LOG_PID                1
+#define LOG_CONS       2
+
+void
+closelog(void);
+
+void
+openlog(const char *ident, int logopt, int facility);
+
+void
+syslog(int priority, const char *message, ...);
+
+#endif
diff --git a/SoftHSMv2/testing/appveyor/APPVEYOR-NOTES.MD b/SoftHSMv2/testing/appveyor/APPVEYOR-NOTES.MD
new file mode 100644 (file)
index 0000000..b2347b0
--- /dev/null
@@ -0,0 +1,27 @@
+# AppVeyor integration with SoftHSMv2 on GitHub
+
+This document describes the process of integrating AppVeyor with SoftHSMv2 on GitHub.
+
+## Integration
+
+### Add project
+
+To add the project, click on the following:
+
+1. New Project
+2. GitHub
+3. opendnssec -> SoftHSMv2 -> Add
+
+### Settings
+
+The following settings where changed.
+
+#### General
+
+* Custom configuration .yml file name: .appveyor.yml
+* Skip branches without appveyor.yml: check
+
+## Dependencies
+
+Prebuilt dependencies (OpenSSL and CppUnit) are currently hosted in a dedicated
+repository by [disig/SoftHSM2-AppVeyor](https://github.com/disig/SoftHSM2-AppVeyor/)
diff --git a/SoftHSMv2/testing/appveyor/appveyor_build.bat b/SoftHSMv2/testing/appveyor/appveyor_build.bat
new file mode 100644 (file)
index 0000000..4e7f41f
--- /dev/null
@@ -0,0 +1,51 @@
+setlocal
+
+echo "Setting visual studio variables"
+
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %VCVARS_PLATFORM%
+@echo on
+
+echo "Setting PATH and other variables"
+set cur_dir=%CD%
+set PATH=%PATH%;%PYTHON_PATH%
+
+echo %cur_dir%
+cd win32
+
+python Configure.py %CONFIGURE_OPTIONS% || goto :error
+
+msbuild softhsm2.sln /p:Configuration="Release" /p:Platform="%MSBUILD_PLATFORM%" /p:PlatformToolset=v140 /target:Build || goto :error
+
+cd %cur_dir%
+
+IF "%ENV_PLATFORM%"=="x86" (set from_dir=%CD%\win32\Release) ELSE (set from_dir=%CD%\win32\x64\Release)
+
+echo "Testing build"
+
+cd %from_dir%
+cryptotest.exe || goto :error
+datamgrtest.exe || goto :error
+handlemgrtest.exe || goto :error
+objstoretest.exe || goto :error
+p11test.exe || goto :error
+sessionmgrtest.exe || goto :error
+slotmgrtest.exe || goto :error
+
+echo "Preparing output package"
+copy %from_dir%\softhsm2.dll %RELEASE_DIR% || goto :error
+copy %from_dir%\softhsm2-dump-file.exe %RELEASE_DIR% || goto :error
+copy %from_dir%\softhsm2-keyconv.exe %RELEASE_DIR% || goto :error
+copy %from_dir%\softhsm2-util.exe %RELEASE_DIR% || goto :error
+copy %cur_dir%\src\lib\common\softhsm2.conf.in %RELEASE_DIR%\softhsm2.conf || goto :error
+
+dir %RELEASE_DIR%
+
+@echo *** BUILD SUCCESSFUL ***
+endlocal
+@exit /b 0
+
+
+:error
+@echo *** BUILD FAILED ***
+endlocal
+@exit /b 1
diff --git a/SoftHSMv2/testing/appveyor/appveyor_download_requirements.ps1 b/SoftHSMv2/testing/appveyor/appveyor_download_requirements.ps1
new file mode 100644 (file)
index 0000000..cc374f5
--- /dev/null
@@ -0,0 +1,80 @@
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+function Unzip
+{
+    param([string]$zipfile, [string]$outpath)
+
+    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
+}
+
+$CURRENT_DIR_PATH = (Get-Item -Path ".\" -Verbose).FullName
+$BUILD_DIR = Join-Path $CURRENT_DIR_PATH build
+
+#prepare directories
+Write-Host "Preparing directories"
+
+$exists = Test-Path build
+if ($exists -eq $false) {
+    mkdir build
+}
+cd build
+
+$exists = Test-Path $env:RELEASE_DIR
+if ($exists -eq $false) {
+    mkdir $env:RELEASE_DIR
+}
+
+$exists = Test-Path python
+if ($exists -eq $true) {
+    Remove-Item python -recurse
+}
+
+$exists = Test-Path "$env:CPPUNIT_PATH"
+if ($exists -eq $true) {
+    Remove-Item "$env:CPPUNIT_PATH" -recurse
+}
+
+$exists = Test-Path "$env:CRYPTO_PACKAGE_PATH"
+if ($exists -eq $true) {
+    Remove-Item "$env:CRYPTO_PACKAGE_PATH" -recurse
+}
+
+mkdir python
+
+Write-Host "Preparing directories - OK"
+
+Write-Host "Downloading needed tools and dependencies"
+
+$exists = Test-Path "$env:CRYPTO_PACKAGE_NAME"
+if ($exists -eq $false) {
+    $source = "https://github.com/disig/SoftHSM2-AppVeyor/raw/master/$env:PACKAGE_VERSION_NAME/$env:CRYPTO_PACKAGE"
+    Invoke-WebRequest $source -OutFile $env:CRYPTO_PACKAGE
+}
+
+$exists = Test-Path "$env:CPPUNIT_PACKAGE"
+if ($exists -eq $false) {
+    $source = "https://github.com/disig/SoftHSM2-AppVeyor/raw/master/$env:CPPUNIT_VERSION_NAME/$env:CPPUNIT_PACKAGE"
+    Invoke-WebRequest $source -OutFile $env:CPPUNIT_PACKAGE
+}
+
+$exists = Test-Path python-3.5.2-embed-win32.zip
+if ($exists -eq $false) {
+    $source = "https://www.python.org/ftp/python/3.5.2/python-3.5.2-embed-win32.zip"
+    Invoke-WebRequest $source -OutFile python-3.5.2-embed-win32.zip
+}
+
+Write-Host "Downloading needed tools and dependencies - OK"
+
+Write-Host "Extracting ..."  
+Unzip "$BUILD_DIR/python-3.5.2-embed-win32.zip" "$env:PYTHON_PATH"
+
+Unzip "$BUILD_DIR/$env:CRYPTO_PACKAGE" "$BUILD_DIR"
+
+Unzip "$BUILD_DIR/$env:CPPUNIT_PACKAGE" "$BUILD_DIR"
+
+dir 
+
+dir "$env:PYTHON_PATH"
+dir "$env:CRYPTO_PACKAGE_PATH"
+dir "$env:CPPUNIT_PATH"
+
+cd $CURRENT_DIR_PATH
\ No newline at end of file
diff --git a/SoftHSMv2/testing/build-botan.sh b/SoftHSMv2/testing/build-botan.sh
new file mode 100644 (file)
index 0000000..fc31217
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+source `dirname "$0"`/lib.sh && init || exit 1
+
+BOTAN="Botan-2.4.0"
+BOTAN_URL="https://botan.randombit.net/releases/$BOTAN.tgz"
+BOTAN_FILENAME="$BOTAN.tgz"
+BOTAN_HASH_TYPE="sha1"
+BOTAN_HASH="212587ae2458d51052c496fbcc79dc4162d33349"
+
+check_if_built botan && exit 0
+start_build botan
+
+BOTAN_SRC=`fetch_src "$BOTAN_URL" "$BOTAN_FILENAME" "$BOTAN_HASH_TYPE" "$BOTAN_HASH"`
+
+build_ok=0
+case "$DISTRIBUTION" in
+       centos | \
+       redhat | \
+       fedora | \
+       sl | \
+       slackware | \
+       ubuntu | \
+       debian | \
+       opensuse | \
+       suse )
+               (
+                       gunzip -c "$BOTAN_SRC" | tar xf - &&
+                       cd "$BOTAN" &&
+                       ./configure.py --prefix="$INSTALL_ROOT" &&
+                       $MAKE &&
+                       $MAKE install
+               ) &&
+               build_ok=1
+               ;;
+       freebsd | \
+       netbsd | \
+       openbsd )
+               opt=""
+               if uname -a 2>/dev/null | grep -q "FreeBSD 10" 2>/dev/null; then
+                       opt="--cc=clang"
+               fi
+               (
+                       gunzip -c "$BOTAN_SRC" | tar xf - &&
+                       cd "$BOTAN" &&
+                       python2.7 ./configure.py --prefix="$INSTALL_ROOT" $opt &&
+                       $MAKE &&
+                       $MAKE install
+               ) &&
+               build_ok=1
+               ;;
+       sunos )
+               platform=`uname -p`
+               opt=""
+               case "$platform" in
+                       i386)
+                               opt="--cpu=i686"
+                               ;;
+
+                       sparc)
+                               opt="--cpu=sparc64"
+                               ;;
+
+                       *)
+                               exit 1
+                               ;;
+               esac
+               (
+                       gunzip -c "$BOTAN_SRC" | tar xf - &&
+                       cd "$BOTAN" &&
+                       ./configure.py --prefix="$INSTALL_ROOT" $opt &&
+                       $MAKE &&
+                       $MAKE install
+               ) &&
+               build_ok=1
+               ;;
+esac
+
+finish
+
+if [ "$build_ok" -eq 1 ]; then
+       set_build_ok botan || exit 1
+       exit 0
+fi
+
+exit 1
diff --git a/SoftHSMv2/testing/build-softhsm2.sh b/SoftHSMv2/testing/build-softhsm2.sh
new file mode 100644 (file)
index 0000000..ec4f43c
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+source `dirname "$0"`/lib.sh && init || exit 1
+
+require botan
+
+check_if_built softhsm2 && exit 0
+start_build softhsm2
+
+build_ok=0
+case "$DISTRIBUTION" in
+       openbsd )
+               export AUTOCONF_VERSION="2.68"
+               export AUTOMAKE_VERSION="1.11"
+               append_ldflags "-L/usr/local/lib"
+               ;;
+esac
+case "$DISTRIBUTION" in
+       centos | \
+       redhat | \
+       fedora | \
+       sl | \
+       slackware | \
+       debian | \
+       ubuntu | \
+       opensuse )
+               (
+                       sh autogen.sh &&
+                       mkdir -p build &&
+                       cd build &&
+                       ../configure --prefix="$INSTALL_ROOT" \
+                               --disable-non-paged-memory \
+                               --with-p11-kit="$INSTALL_ROOT/usr/local/share/p11-kit/modules" \
+                               --with-migrate \
+                               --with-crypto-backend=botan \
+                               --with-botan="$INSTALL_ROOT" &&
+                       $MAKE &&
+                       $MAKE check &&
+                       $MAKE install &&
+                       cp "src/lib/common/softhsm2.conf" "$INSTALL_ROOT/etc/softhsm2.conf.build"
+               ) &&
+               build_ok=1
+               ;;
+       netbsd )
+               (
+                       sh autogen.sh &&
+                       mkdir -p build &&
+                       cd build &&
+                       ../configure --prefix="$INSTALL_ROOT" \
+                               --disable-non-paged-memory \
+                               --with-p11-kit="$INSTALL_ROOT/usr/local/share/p11-kit/modules" \
+                               --with-migrate \
+                               --with-crypto-backend=botan \
+                               --with-botan="$INSTALL_ROOT" \
+                               --with-sqlite3=/usr/pkg &&
+                       $MAKE &&
+                       $MAKE check &&
+                       $MAKE install &&
+                       cp "src/lib/common/softhsm2.conf" "$INSTALL_ROOT/etc/softhsm2.conf.build"
+               ) &&
+               build_ok=1
+               ;;
+       freebsd | \
+       openbsd )
+               (
+                       sh autogen.sh &&
+                       mkdir -p build &&
+                       cd build &&
+                       ../configure --prefix="$INSTALL_ROOT" \
+                               --disable-non-paged-memory \
+                               --with-p11-kit="$INSTALL_ROOT/usr/local/share/p11-kit/modules" \
+                               --with-migrate \
+                               --with-crypto-backend=botan \
+                               --with-botan="$INSTALL_ROOT" \
+                               --with-sqlite3=/usr/local &&
+                       $MAKE &&
+                       $MAKE check &&
+                       $MAKE install &&
+                       cp "src/lib/common/softhsm2.conf" "$INSTALL_ROOT/etc/softhsm2.conf.build"
+               ) &&
+               build_ok=1
+               ;;
+       sunos | \
+       suse )
+               (
+                       sh autogen.sh &&
+                       mkdir -p build &&
+                       cd build &&
+                       ../configure --prefix="$INSTALL_ROOT" \
+                               --disable-non-paged-memory \
+                               --with-p11-kit="$INSTALL_ROOT/usr/local/share/p11-kit/modules" \
+                               --with-migrate \
+                               --with-crypto-backend=botan \
+                               --with-botan="$INSTALL_ROOT" &&
+                       $MAKE &&
+                       $MAKE check &&
+                       $MAKE install &&
+                       cp "src/lib/common/softhsm2.conf" "$INSTALL_ROOT/etc/softhsm2.conf.build"
+               ) &&
+               build_ok=1
+               ;;
+esac
+
+finish
+
+if [ "$build_ok" -eq 1 ]; then
+       set_build_ok softhsm2 || exit 1
+       exit 0
+fi
+
+exit 1
diff --git a/SoftHSMv2/testing/lib.sh b/SoftHSMv2/testing/lib.sh
new file mode 100644 (file)
index 0000000..8a03846
--- /dev/null
@@ -0,0 +1,2232 @@
+exit ()
+{
+       if [ -n "$_CLEANUP_TEST" ]; then
+               rm -f "$WORKSPACE_ROOT/.testing" 2>/dev/null
+               rm -f "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null
+       fi
+       
+       if [ -n "$_SYSLOG_TRACE_PID" ]; then
+               case "$DISTRIBUTION" in
+                       debian | \
+                       ubuntu | \
+                       redhat | \
+                       centos | \
+                       sl | \
+                       slackware | \
+                       opensuse | \
+                       suse | \
+                       freebsd | \
+                       netbsd | \
+                       openbsd | \
+                       sunos )
+                               kill -TERM "$_SYSLOG_TRACE_PID" 2>/dev/null &&
+                               {
+                                       wait "$_SYSLOG_TRACE_PID"
+                                       unset _SYSLOG_TRACE_PID
+                               }
+                               ;;
+               esac
+       fi
+               
+       builtin exit $*
+}
+
+append_path ()
+{
+       if [ -d "$1" ]; then
+               if [ -n "$PATH" ]; then
+                       echo "$PATH" | $GREP -q -- "$1:" 2>/dev/null && return;
+                       echo "$PATH" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       PATH="$PATH:$1"
+               else
+                       PATH="$1"
+               fi
+               export PATH
+       fi
+}
+
+prepend_path ()
+{
+       if [ -d "$1" ]; then
+               if [ -n "$PATH" ]; then
+                       echo "$PATH" | $GREP -q -- "$1:" 2>/dev/null && return;
+                       echo "$PATH" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       PATH="$1:$PATH"
+               else
+                       PATH="$1"
+               fi
+               export PATH
+       fi
+}
+
+append_cflags ()
+{
+       if [ -n "$1" ]; then
+               if [ -n "$CFLAGS" ]; then
+                       echo "$CFLAGS" | $GREP -q -- "$1 " 2>/dev/null && return;
+                       echo "$CFLAGS" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       CFLAGS="$CFLAGS $1"
+               else
+                       CFLAGS="$1"
+               fi
+               export CFLAGS
+       fi
+}
+
+append_cppflags ()
+{
+       if [ -n "$1" ]; then
+               if [ -n "$CPPFLAGS" ]; then
+                       echo "$CPPFLAGS" | $GREP -q -- "$1 " 2>/dev/null && return;
+                       echo "$CPPFLAGS" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       CPPFLAGS="$CPPFLAGS $1"
+               else
+                       CPPFLAGS="$1"
+               fi
+               export CPPFLAGS
+       fi
+}
+
+append_ldflags ()
+{
+       if [ -n "$1" ]; then
+               if [ -n "$LDFLAGS" ]; then
+                       echo "$LDFLAGS" | $GREP -q -- "$1 " 2>/dev/null && return;
+                       echo "$LDFLAGS" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       LDFLAGS="$LDFLAGS $1"
+               else
+                       LDFLAGS="$1"
+               fi
+               export LDFLAGS
+       fi
+}
+
+append_ld_library_path ()
+{
+       if [ -d "$1" ]; then
+               if [ -n "$LD_LIBRARY_PATH" ]; then
+                       echo "$LD_LIBRARY_PATH" | $GREP -q -- "$1:" 2>/dev/null && return;
+                       echo "$LD_LIBRARY_PATH" | $GREP -q -- "$1\$" 2>/dev/null && return;
+                       LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$1"
+               else
+                       LD_LIBRARY_PATH="$1"
+               fi
+               export LD_LIBRARY_PATH
+       fi
+}
+
+find_jenkins_workspace_root ()
+{
+       if [ -z "$WORKSPACE" -o ! -d "$WORKSPACE" ]; then
+               echo "find_jenkins_workspace_root: Unable to find workspace root since no WORKSPACE has been defined" >&2
+               return 1
+       fi
+
+       local workspace="$WORKSPACE"
+       local max_iter=20
+       local currdir
+       
+       while [ "$max_iter" -gt 0 ] 2>/dev/null; do
+               # check if the last dir on the path is workspace
+               currdir=`echo "$workspace" | sed 's%.*/%%' 2>/dev/null`
+               if [ "$currdir" = "workspace" ]; then
+                       break
+               fi
+               
+               # remove the last dir on the path
+               workspace=`echo "$workspace" | sed 's%/[^/]*$%%' 2>/dev/null`
+               
+               max_iter=$(( max_iter - 1))
+       done
+
+       if [ -n "$workspace" -a "$max_iter" -gt 0 ] 2>/dev/null; then
+               WORKSPACE_ROOT="$workspace"
+               return 0
+       fi
+
+       echo "find_jenkins_workspace_root: Failed to find workspace root in WORKSPACE=$WORKSPACE" >&2
+       return 1
+}
+
+find_program ()
+{
+       if [ -n "$1" ]; then
+               local path=`which "$1" 2>/dev/null`
+               if [ -n "$path" -a -x "$path" ]; then
+                       echo "$path"
+                       return 0
+               fi
+       fi
+       
+       return 1
+}
+
+find_make ()
+{
+       local make
+       local program
+       local programs="gmake make"
+       
+       case "$DISTRIBUTION" in
+               freebsd )
+                       programs="gmake"
+                       ;;
+       esac
+       
+       for program in $programs; do
+               make=`find_program "$program"`
+               if [ -n "$make" ]; then
+                       export MAKE="$make"
+                       return 0
+               fi
+       done
+       
+       return 1
+}
+
+find_m4 ()
+{
+       local m4
+       local program
+       
+       for program in gm4 m4; do
+               m4=`find_program "$program"`
+               if [ -n "$m4" ]; then
+                       export M4="$m4"
+                       return 0
+               fi
+       done
+       
+       return 1
+}
+
+find_md5sum ()
+{
+    local md5sum
+    local program
+    
+    for program in md5sum gmd5sum md5; do
+               md5sum=`find_program "$program"`
+               if [ -n "$md5sum" ]; then
+                   MD5SUM="$md5sum"
+                   case "$program" in
+                       md5)
+                       MD5SUM="$MD5SUM -q"
+                       ;;
+                   esac
+                       export MD5SUM
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_sha1sum ()
+{
+    local shasum
+    local program
+
+    for program in sha1sum gsha1sum shasum sha1; do
+       shasum=`find_program "$program"`
+       if [ -n "$shasum" ]; then
+               SHA1SUM="$shasum"
+               case "$program" in
+                       shasum)
+                       SHA1SUM="$SHA1SUM -a 1"
+                       ;;
+                       sha1)
+                       SHA1SUM="$SHA1SUM -q"
+                       ;;
+               esac
+               export SHA1SUM
+               return 0
+       fi
+    done
+
+    return 1
+}
+
+find_sha256sum ()
+{
+       local sha256sum
+       local program
+       
+       for program in sha256sum gsha256sum shasum sha256; do
+               sha256sum=`find_program "$program"`
+               if [ -n "$sha256sum" ]; then
+                       SHA256SUM="$shasum"
+               case "$program" in
+                       shasum)
+                       SHA256SUM="$SHA256SUM -a 256"
+                       ;;
+                       sha256)
+                       SHA256SUM="$SHA256SUM -q"
+                       ;;
+               esac
+                       export SHA256SUM
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_wget ()
+{
+       local wget
+       local program
+       
+       for program in wget; do
+               wget=`find_program "$program"`
+               if [ -n "$wget" ]; then
+                       export WGET="$wget"
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_ccache ()
+{
+       local ccache
+       local program
+       local path
+       
+       for program in ccache; do
+               ccache=`find_program "$program"`
+               if [ -n "$ccache" ]; then
+                       export CCACHE="$ccache"
+                       for path in /usr/lib64/ccache /usr/lib/ccache /usr/local/lib64/ccache /usr/local/lib/ccache; do
+                               if [ -d "$path" ]; then
+                                       prepend_path "$path"
+                                       break
+                               fi
+                       done
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_cc ()
+{
+       local cc
+       local program
+       
+       for program in cc gcc; do
+               cc=`find_program "$program"`
+               if [ -n "$cc" ]; then
+                       export CC="$cc"
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_cxx ()
+{
+       local cxx
+       local program
+       
+       for program in c++ g++; do
+               cxx=`find_program "$program"`
+               if [ -n "$cxx" ]; then
+                       export CXX="$cxx"
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_tee ()
+{
+       local tee
+       local program
+       
+       for program in tee; do
+               tee=`find_program "$program"`
+               if [ -n "$tee" ]; then
+                       export TEE="$tee"
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+find_date ()
+{
+       local date
+       local program
+       local time_now
+       
+       for program in date; do
+               date=`find_program "$program"`
+               if [ -n "$date" ]; then
+                       time_now=`$date '+%s' 2>/dev/null`
+                       if [ -n "$time_now" -a "$time_now" -gt 0 ] 2>/dev/null; then
+                               export DATE="$date"
+                               return 0
+                       fi
+               fi
+       done
+
+       return 1
+}
+
+find_tail ()
+{
+       local tail
+       local tail_follow
+       local program
+       local programs="tail"
+       
+       case "$DISTRIBUTION" in
+               sunos )
+                       programs="gtail"
+                       ;;
+       esac
+               
+       for program in $programs; do
+               tail=`find_program "$program"`
+               if [ -n "$tail" ]; then
+                       break
+               fi
+       done
+
+       if [ -z "$tail" ]; then
+               return 1
+       fi
+
+       case "$DISTRIBUTION" in
+               debian | \
+               ubuntu | \
+               redhat | \
+               centos | \
+               sl | \
+               slackware | \
+               opensuse | \
+               suse | \
+               sunos )
+                       tail_follow="$tail --follow=name -n 0"
+                       ;;
+               freebsd | \
+               netbsd )
+                       tail_follow="$tail -f -F -n 0"
+                       ;;
+               openbsd )
+                       tail_follow="$tail -f -n 0"
+                       ;;
+       esac
+
+       if [ -z "$tail_follow" ]; then
+               return 1
+       fi
+       
+       export TAIL="$tail"
+       export TAIL_FOLLOW="$tail_follow"
+
+       return 0
+}
+
+find_grep ()
+{
+       local grep
+       local program
+
+       for program in ggrep grep; do
+               grep=`find_program "$program"`
+               if [ -n "$grep" ]; then
+                       export GREP="$grep"
+                       return
+               fi
+       done
+
+       return 1
+}
+
+setup_install_root ()
+{
+       if [ -n "$INSTALL_ROOT" ]; then
+               if [ -d "$INSTALL_ROOT" ]; then
+                       return 0
+               else
+                       return 1
+               fi
+       fi
+
+       if [ ! -d "$WORKSPACE_ROOT/root" ]; then
+               if ! mkdir -p "$WORKSPACE_ROOT/root" 2>/dev/null; then
+                       echo "setup_install_root: Unable to create INSTALL_ROOT at $WORKSPACE_ROOT/root" >&2
+                       return 1
+               fi
+       fi
+       
+       if [ -n "$INSTALL_TAG" ]; then
+               if [ ! -d "$WORKSPACE_ROOT/root/$INSTALL_TAG" ]; then
+                       if ! mkdir -p "$WORKSPACE_ROOT/root/$INSTALL_TAG" 2>/dev/null; then
+                               echo "setup_install_root: Unable to create INSTALL_ROOT at $WORKSPACE_ROOT/root/$INSTALL_TAG" >&2
+                               return 1
+                       fi
+               fi
+               
+               INSTALL_ROOT="$WORKSPACE_ROOT/root/$INSTALL_TAG"
+
+               if [ -d "$INSTALL_ROOT/bin" ]; then
+                       prepend_path "$INSTALL_ROOT/bin"
+               fi
+               if [ -d "$INSTALL_ROOT/sbin" ]; then
+                       prepend_path "$INSTALL_ROOT/sbin"
+               fi
+               if [ -d "$INSTALL_ROOT/lib64" ]; then
+                       append_ldflags "-L$INSTALL_ROOT/lib64"
+                       append_ld_library_path "$INSTALL_ROOT/lib64"
+               fi
+               if [ -d "$INSTALL_ROOT/lib" ]; then
+                       append_ldflags "-L$INSTALL_ROOT/lib"
+                       append_ld_library_path "$INSTALL_ROOT/lib"
+               fi
+               if [ -d "$INSTALL_ROOT/include" ]; then
+                       append_cflags "-I$INSTALL_ROOT/include"
+                       append_cppflags "-I$INSTALL_ROOT/include"
+               fi
+               
+               return 0
+       fi
+       
+       echo "setup_install_root: INSTALL_TAG or INSTALL_ROOT is not set, need to know in where to build/test" >&2
+       return 1
+}
+
+detect_revision ()
+{
+       if [ -z "$REVISION" ]; then
+               if [ -n "$SVN_REVISION" ]; then
+                       REVISION="$SVN_REVISION"
+               elif [ -n "$GIT_COMMIT" ]; then
+                       REVISION="$GIT_COMMIT"
+               fi
+       fi
+}
+       
+detect_distribution ()
+{
+       DISTRIBUTION="UNKNOWN"
+       
+       if [ -f "/etc/debian_version" ]; then
+               if uname -a 2>/dev/null | $GREP -q -i ubuntu 2>/dev/null; then
+                       DISTRIBUTION="ubuntu"
+               else
+                       DISTRIBUTION="debian"
+               fi
+       elif [ -f "/etc/redhat-release" ]; then
+               if $GREP -q -i centos /etc/redhat-release 2>/dev/null; then
+                       DISTRIBUTION="centos"
+               elif $GREP -q -i fedora /etc/redhat-release 2>/dev/null; then
+                       DISTRIBUTION="fedora"
+               elif $GREP -q -i "scientific linux" /etc/redhat-release 2>/dev/null; then
+                       DISTRIBUTION="sl"
+               else
+                       DISTRIBUTION="redhat"
+               fi
+       elif [ -f "/etc/slackware-version" ]; then
+               DISTRIBUTION="slackware"
+       elif [ -f "/etc/os-release" ]; then
+               if $GREP -q -i opensuse /etc/os-release 2>/dev/null; then
+                       DISTRIBUTION="opensuse"
+               fi
+       elif [ -f "/etc/SuSE-release" ]; then
+               if $GREP -q -i "suse linux enterprise" /etc/SuSE-release 2>/dev/null; then
+                       DISTRIBUTION="suse"
+               fi
+       elif uname -a 2>/dev/null | $GREP -q -i freebsd 2>/dev/null; then
+               DISTRIBUTION="freebsd"
+       elif uname -a 2>/dev/null | $GREP -q -i sunos 2>/dev/null; then
+               DISTRIBUTION="sunos"
+       elif uname -a 2>/dev/null | $GREP -q -i openbsd 2>/dev/null; then
+               DISTRIBUTION="openbsd"
+       elif uname -a 2>/dev/null | $GREP -q -i netbsd 2>/dev/null; then
+               DISTRIBUTION="netbsd"
+       fi
+
+       export DISTRIBUTION
+}
+
+init ()
+{
+       unset _CLEANUP_TEST
+       unset _SYSLOG_TRACE_PID
+       unset PRE_TEST
+       unset POST_TEST
+       
+       find_grep || exit 1
+       detect_revision
+       detect_distribution
+       find_jenkins_workspace_root || exit 1
+       setup_install_root || exit 1
+       find_make || exit 1
+       find_m4 || exit 1
+       find_wget || exit 1
+       find_md5sum || exit 1
+       find_sha1sum || exit 1
+       find_sha256sum || exit 1
+       find_ccache # ccache needs to be found before cc/cxx
+       find_cc || exit 1
+       find_cxx || exit 1
+       find_tee || exit 1
+       find_date || exit 1
+       find_tail || exit 1
+       
+       # prevent CTRL-Z and CTRL-C
+    trap "" SIGINT 2>/dev/null >/dev/null
+    trap "" SIGTSTP 2>/dev/null >/dev/null
+    
+       return 0
+}
+
+finish ()
+{
+       local core
+
+       find "$WORKSPACE" "$INSTALL_ROOT" -name '*core' -type f 2>/dev/null | while read core; do
+               chmod a+r "$core" 2>/dev/null
+       done
+}
+
+check_if_built ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: check_if_built <name tag>" >&2
+               exit 1
+       fi
+       
+       if [ -z "$REVISION" ]; then
+               echo "check_if_built: No REVISION is set, can't check if build is ok!" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+       
+       if [ -f "$INSTALL_ROOT/.$name_tag.build" ]; then
+               local build_rev=`cat "$INSTALL_ROOT/.$name_tag.build" 2>/dev/null`
+               
+               if [ "$REVISION" = "$build_rev" ]; then
+                       return 0
+               fi
+       fi
+       
+       return 1
+}
+
+start_build ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: start_build <name tag>" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+       
+       if [ -f "$INSTALL_ROOT/.$name_tag.ok" ]; then
+               if ! rm "$INSTALL_ROOT/.$name_tag.ok" 2>/dev/null; then
+                       echo "start_build: can't remove old ok file $INSTALL_ROOT/.$name_tag.ok !" >&2
+                       exit 1
+               fi
+       fi
+
+       echo "start_build: Starting build for $name_tag on $DISTRIBUTION"
+       return 0
+}
+
+set_build_ok ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: set_build_ok <name tag>" >&2
+               exit 1
+       fi
+       
+       if [ -z "$REVISION" ]; then
+               echo "set_build_ok: No REVISION is set, can't check if build is ok!" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+
+       if [ -f "$INSTALL_ROOT/.$name_tag.ok" ]; then
+               echo "set_build_ok: Build already mark ok, this should not happend. Did you forget to start_build?" >&2
+               exit 1
+       fi
+
+       echo "$REVISION" > "$INSTALL_ROOT/.$name_tag.build"
+
+       if [ -f "$INSTALL_ROOT/.$name_tag.build" ]; then
+               local build_rev=`cat "$INSTALL_ROOT/.$name_tag.build" 2>/dev/null`
+               
+               if [ "$REVISION" = "$build_rev" ]; then
+                       if ! touch "$INSTALL_ROOT/.$name_tag.ok" 2>/dev/null; then
+                               echo "set_build_ok: Can't tag build ok $INSTALL_ROOT/.$name_tag.ok !" >&2
+                               return 1
+                       fi
+                       return 0
+               fi
+       fi
+       
+       echo "set_build_ok: Was not able to tag build ok!" >&2
+       return 1
+}
+
+check_if_tested ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: check_if_tested <name tag>" >&2
+               exit 1
+       fi
+       
+       if [ -z "$REVISION" ]; then
+               echo "check_if_tested: No REVISION is set, can't check if test is ok!" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+       
+       if [ -f "$INSTALL_ROOT/.$name_tag.test" ]; then
+               local build_rev=`cat "$INSTALL_ROOT/.$name_tag.test" 2>/dev/null`
+               
+               if [ "$REVISION" = "$build_rev" ]; then
+                   if [ "$INSTALL_ROOT/.$name_tag.junit" ]; then
+                       if ! cp -- "$INSTALL_ROOT/.$name_tag.junit" "$WORKSPACE/junit.xml" 2>/dev/null; then
+                           return 1
+                       fi
+                   fi
+                   if [ -f "$WORKSPACE/junit.xml" ]; then
+                       touch "$WORKSPACE/junit.xml"
+                   fi
+                       return 0
+               fi
+       fi
+       
+       return 1
+}
+
+start_test ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: start_test <name tag>" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+#      local time_start=`$DATE '+%s' 2>/dev/null`
+#      local timeout=3600
+#      local time_stop=$(( time_start + timeout ))
+#      local time_now
+#      local build_tag
+#      
+#      echo "$BUILD_TAG $$" > "$WORKSPACE_ROOT/.testing.$$"
+#      build_tag=`cat "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null`
+#      if [ "$build_tag" != "$BUILD_TAG $$" ]; then
+#              echo "start_test: Unable to add test lock!" >&2
+#              rm -f "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null
+#              return 1
+#      fi
+#      
+#      while true; do
+#              if [ ! -f "$WORKSPACE_ROOT/.testing" ]; then
+#                      if ln -s "$WORKSPACE_ROOT/.testing.$$" "$WORKSPACE_ROOT/.testing" 2>/dev/null; then
+#                              build_tag=`cat "$WORKSPACE_ROOT/.testing" 2>/dev/null`
+#                              if [ "$build_tag" = "$BUILD_TAG $$" ]; then
+#                                      if [ -f "$INSTALL_ROOT/.$name_tag.ok.test" ]; then
+#                                              if ! rm "$INSTALL_ROOT/.$name_tag.ok.test" 2>/dev/null; then
+#                                                      echo "start_test: can't remove old ok file $INSTALL_ROOT/.$name_tag.ok.test !" >&2
+#                                                      exit 1
+#                                              fi
+#                                      fi
+#                                      export _CLEANUP_TEST=1
+#                                      return 0
+#                              fi
+#                      fi
+#              fi
+#
+#              if [ -z "$time_now" ]; then
+#                      echo "start_test: waiting for other tests to finish (timeout $timeout)"
+#              fi
+#              
+#              time_now=`$DATE '+%s' 2>/dev/null`
+#              if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+#                      break
+#              fi
+#              if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+#                      echo "start_test: Invalid timestamp from date!" >&2
+#                      exit 1
+#              fi
+#              sleep 2
+#      done
+#      
+#      echo "start_test: Unable to get test lock, timeout" >&2
+#      rm -f "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null
+#      exit 1
+
+       if [ -f "$INSTALL_ROOT/.$name_tag.ok.test" ]; then
+               if ! rm "$INSTALL_ROOT/.$name_tag.ok.test" 2>/dev/null; then
+                       echo "start_test: can't remove old ok file $INSTALL_ROOT/.$name_tag.ok.test !" >&2
+                       exit 1
+               fi
+       fi
+       
+       echo "start_test: Starting test for $name_tag on $DISTRIBUTION"
+       return 0
+}
+
+stop_test ()
+{
+#      local build_tag
+#      
+#      if [ ! -f "$WORKSPACE_ROOT/.testing" ]; then
+#              echo "stop_test: Called without a test lock file, this should not happen!" >&2
+#              return 1
+#      fi
+#      
+#      build_tag=`cat "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null`
+#      if [ "$build_tag" != "$BUILD_TAG $$" ]; then
+#              echo "stop_test: Our test lock does not exist or is not our own!" >&2
+#              return 1
+#      fi
+#      
+#      build_tag=`cat "$WORKSPACE_ROOT/.testing" 2>/dev/null`
+#      if [ "$build_tag" != "$BUILD_TAG $$" ]; then
+#              echo "stop_test: Content of test lock changed during test!" >&2
+#              rm -f "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null
+#              return 1
+#      fi
+#      
+#      rm -f "$WORKSPACE_ROOT/.testing" 2>/dev/null
+#      rm -f "$WORKSPACE_ROOT/.testing.$$" 2>/dev/null
+#      export _CLEANUP_TEST=""
+       return 0
+}
+
+set_test_ok ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: set_test_ok <name tag>" >&2
+               exit 1
+       fi
+       
+       if [ -z "$REVISION" ]; then
+               echo "set_test_ok: No REVISION is set, can't check if test is ok!" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+
+       if [ -f "$INSTALL_ROOT/.$name_tag.ok.test" ]; then
+               echo "set_test_ok: Test already mark ok, this should not happend. Did you forget to start_test?" >&2
+               exit 1
+       fi
+
+       echo "$REVISION" > "$INSTALL_ROOT/.$name_tag.test"
+
+       if [ -f "$INSTALL_ROOT/.$name_tag.test" ]; then
+               local test_rev=`cat "$INSTALL_ROOT/.$name_tag.test" 2>/dev/null`
+               
+               if [ "$REVISION" = "$test_rev" ]; then
+                       if ! touch "$INSTALL_ROOT/.$name_tag.ok.test" 2>/dev/null; then
+                               echo "set_test_ok: Can't tag test ok $INSTALL_ROOT/.$name_tag.ok.test !" >&2
+                               return 1
+                       fi
+            if [ -f "$WORKSPACE/junit.xml" ]; then
+                if ! cp -- "$WORKSPACE/junit.xml" "$INSTALL_ROOT/.$name_tag.junit" 2>/dev/null; then
+                     echo "set_test_ok: Can't copy $WORKSPACE/junit.xml to $INSTALL_ROOT/.$name_tag.junit !" >&2
+                     return 1
+                 fi
+            fi
+                       return 0
+               fi
+       fi
+       
+       echo "set_test_ok: Was not able to tag test ok!" >&2
+       return 1
+}
+
+
+require ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: require <name tag>" >&2
+               exit 1
+       fi
+       
+       local name_tag="$1"
+       
+       if [ ! -f "$INSTALL_ROOT/.$name_tag.ok" ]; then
+               echo "require: Required program $name_tag not found or not built!" >&2
+               exit 1
+       fi
+
+       if [ ! -f "$INSTALL_ROOT/.$name_tag.build" ]; then
+               echo "require: Required program $name_tag corrupt, can't find build version!" >&2
+               exit 1
+       fi
+       
+       local require_rev=`cat "$INSTALL_ROOT/.$name_tag.build" 2>/dev/null`
+
+       if [ -z "$require_rev" ]; then
+               echo "require: There is no build version for $name_tag!" >&2
+               exit 1
+       fi
+       
+       export REVISION="$REVISION-$name_tag:$require_rev"
+}
+
+check_hash ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: check_hash <filename> <type> <hash>" >&2
+               exit 1
+       fi
+       
+       local filename="$1"
+       local type="$2"
+       local hash="$3"
+       local file_hash
+
+       if [ -f "$filename" ]; then
+               case "$type" in
+                       md5)
+               file_hash=`$MD5SUM "$filename" 2>/dev/null | awk '{print $1}'`
+               ;;
+                       sha1)
+                       file_hash=`$SHA1SUM "$filename" 2>/dev/null | awk '{print $1}'`
+                       ;;
+                       sha256)
+                       file_hash=`$SHA256SUM "$filename" 2>/dev/null | awk '{print $1}'`
+                       ;;
+               esac
+               if [ -n "$file_hash" -a "$hash" = "$file_hash" ]; then
+                       return 0
+               fi
+       fi
+       
+       return 1
+}
+
+fetch_src ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ]; then
+               echo "usage: fetch_src <url> <filename> <type> <hash>" >&2
+               exit 1
+       fi
+       
+       local url="$1"
+       local filename="$2"
+       local type="$3"
+       local hash="$4"
+       local path_filename
+       
+       if [ ! -d "$WORKSPACE_ROOT/cache" ]; then
+               if ! mkdir -p "$WORKSPACE_ROOT/cache" 2>/dev/null; then
+                       echo "fetch_src: Unable to create cache directory $WORKSPACE_ROOT/cache!" >&2
+                       exit 1
+               fi
+       fi
+
+       path_filename="$WORKSPACE_ROOT/cache/$filename"
+
+       if [ -f "$path_filename" ]; then
+               if check_hash "$path_filename" "$type" "$hash"; then
+                       echo "$path_filename"
+                       return 0
+               fi
+               if ! rm "$path_filename" 2>/dev/null; then
+                       echo "fetch_src: Unable to remove old invalid file $path_filename!" >&2
+                       exit 1
+               fi
+       fi
+
+       if ! $WGET -O "$path_filename" "$url" 2>/dev/null; then
+               echo "fetch_src: wget failed!" >&2
+               rm -f "$path_filename" 2>/dev/null
+               exit 1
+       fi
+       
+       if [ ! -f "$path_filename" ]; then
+               echo "fetch_src: File at $url not found at $path_filename!" >&2
+               exit 1
+       fi
+       
+       if ! check_hash "$path_filename" "$type" "$hash"; then
+               echo "fetch_src: Checksum does not match for $path_filename!" >&2
+               exit 1
+       fi
+       
+       echo "$path_filename"
+}
+
+log_init ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: log_this <log name>" >&2
+               exit 1
+       fi
+       
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+
+       touch "$log_stderr" "$log_stdout"
+}
+
+log_this ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: log_this <log name> <command> [options ...]" >&2
+               exit 1
+       fi
+       
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       shift
+
+       touch "$log_stderr" "$log_stdout"
+               
+       echo "log_this: logging $name for command: $*"
+       $* 2>>"$log_stderr" >>"$log_stdout"
+}
+
+log_this_timeout ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: log_this_timeout <log name> <timeout in seconds> <command ... >" >&2
+               exit 1
+       fi
+       
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local timeout="$2"
+       local pid
+       shift 2
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "log_this_timeout: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "log_this_timeout: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "log_this_timeout: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       touch "$log_stderr" "$log_stdout"
+       
+       echo "log_this_timeout: logging $name with timeout $timeout for command: $*"
+       ( $* 2>>"$log_stderr" >>"$log_stdout" ) &
+       pid="$!"
+       
+       if [ -z "$pid" -o "$pid" -le 0 ] 2>/dev/null; then
+               echo "log_this_timeout: No pid from backgrounded program?" >&2
+               return 1
+       fi
+       
+       while true; do
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "log_this_timeout: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               if ! kill -0 "$pid" 2>/dev/null; then
+                       wait "$pid"
+                       return "$?"
+               fi
+               sleep 1
+       done
+
+       kill -TERM "$pid"
+       sleep 1
+       if kill -0 "$pid" 2>/dev/null; then
+               kill -KILL "$pid"
+       fi      
+       return 1
+}
+
+log_force_stop ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: log_force_stop <log name> [grace period in seconds]" >&2
+               exit 1
+       fi
+
+       local name="$1"
+       local grace="$2"
+       local log_stderr_pid="_log_pid.$BUILD_TAG.$name.stderr"
+       local log_stdout_pid="_log_pid.$BUILD_TAG.$name.stdout"
+       local stderr_pid
+       local stdout_pid
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop=$(( time_start + 5 ))
+       local time_now
+
+       if [ -n "$grace" -a "$grace" -gt 0 ] 2>/dev/null; then
+               time_stop=$(( time_start + grace ))
+       fi
+
+       while true; do
+               if [ ! -f "$log_stderr_pid" -a ! -f "$log_stdout_pid" ]; then
+                       break
+               fi
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break;
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "log_force_stop: Invalid timestamp from date!" >&2
+                       return 1
+               fi
+               sleep 1
+       done
+
+       if [ -f "$log_stderr_pid" ]; then
+               stderr_pid=`cat "$log_stderr_pid"`
+               if [ "$stderr_pid" -gt 0 ] 2>/dev/null; then
+                       kill -TERM "$stderr_pid" 2>/dev/null
+               fi
+               rm -f "$log_stderr_pid"
+       fi
+
+       if [ -f "$log_stdout_pid" ]; then
+               stdout_pid=`cat "$log_stdout_pid"`
+               if [ "$stdout_pid" -gt 0 ] 2>/dev/null; then
+                       kill -TERM "$stdout_pid" 2>/dev/null
+               fi
+               rm -f "$log_stdout_pid"
+       fi
+       
+       return 0
+}
+
+log_grep ()
+{
+       local output=""
+       OPTIND=1
+       while getopts ":o" opt; do
+               case "$opt" in
+                       o)
+                               output=1
+                               ;;
+                       \?)
+                               echo "log_grep: Invalid option: -$OPTARG" >&2
+                               exit 1
+                               ;;
+               esac
+       done
+       shift $((OPTIND-1))
+
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: log_grep [-o] <log name> <stdout|stderr|both> <grep string ...>" >&2
+               exit 1
+       fi
+
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       local type="$2"
+       local grep_string="$3"
+       local log_files
+       
+       case "$type" in
+               stdout)
+               if [ ! -f "$log_stdout" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout"
+               ;;
+               stderr)
+               if [ ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stderr"
+               ;;
+               both)
+               if [ ! -f "$log_stdout" -a ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout $log_stderr"
+               ;;
+       esac
+       
+       if [ -z "$log_files" ]; then
+               echo "log_grep: Wrong type of log file specified, should be stdout, stderr or both!" >&2
+               exit 1
+       fi
+
+       if [ -n "$output" ]; then
+               $GREP -- "$grep_string" $log_files 2>/dev/null
+       else
+               echo "log_grep: greping in $name for: $grep_string"
+               $GREP -q -- "$grep_string" $log_files 2>/dev/null
+       fi
+}
+
+log_grep_count ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$3" ]; then
+               echo "usage: log_grep_count <log name> <stdout|stderr|both> <count> <grep string ...>" >&2
+               exit 1
+       fi
+
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       local type="$2"
+       local grep_string="$3"
+       local count="$4"
+       local log_files
+       local count_found
+       
+       case "$type" in
+               stdout)
+               if [ ! -f "$log_stdout" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout"
+               ;;
+               stderr)
+               if [ ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stderr"
+               ;;
+               both)
+               if [ ! -f "$log_stdout" -a ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout $log_stderr"
+               ;;
+       esac
+       
+       if [ -z "$log_files" ]; then
+               echo "log_grep_count: Wrong type of log file specified, should be stdout, stderr or both!" >&2
+               exit 1
+       fi
+
+       echo "log_grep_count: greping in $name, should find $count of: $grep_string"
+       count_found=`$GREP -- "$grep_string" $log_files 2>/dev/null | wc -l 2>/dev/null`
+       
+       if [ "$count_found" -eq "$count" ] 2>/dev/null; then
+               return 0
+       fi
+       
+       return 1
+}
+
+log_waitfor ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$3" ]; then
+               echo "usage: log_waitfor <log name> <stdout|stderr|both> <timeout in seconds> <grep string ...>" >&2
+               exit 1
+       fi
+
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       local type="$2"
+       local timeout="$3"
+       local grep_string="$4"
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local log_files
+
+       case "$type" in
+               stdout)
+               if [ ! -f "$log_stdout" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout"
+               ;;
+               stderr)
+               if [ ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stderr"
+               ;;
+               both)
+               if [ ! -f "$log_stdout" -a ! -f "$log_stderr" ]; then
+                       return 1
+               fi
+               log_files="$log_stdout $log_stderr"
+               ;;
+       esac
+       
+       if [ -z "$log_files" ]; then
+               echo "log_waitfor: Wrong type of log file specified, should be stdout, stderr or both!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "log_waitfor: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "log_waitfor: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "log_waitfor: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       echo "log_waitfor: waiting for log $name to contain (timeout $timeout): $grep_string"
+       while true; do
+               if $GREP -q -- "$grep_string" $log_files 2>/dev/null; then
+                       return 0
+               fi
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "log_waitfor: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               sleep 2
+       done
+       return 1
+}
+
+log_cleanup ()
+{
+       local pid_file
+       local pid
+
+       ls _log_pid* 2>/dev/null | while read pid_file; do
+               pid=`cat $pid_file 2>/dev/null`
+
+               if [ -n "$pid" -a "$pid" -gt 0 ] 2>/dev/null; then
+                       kill -TERM "$pid" 2>/dev/null
+                       rm -f "$pid_file" 2>/dev/null
+               fi
+       done
+
+       rm -f "_log.$BUILD_TAG"* 2>/dev/null
+}
+
+log_remove ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: log_remove <log name>" >&2
+               exit 1
+       fi
+
+       local name="$1"
+       local log_stderr="_log.$BUILD_TAG.$name.stderr"
+       local log_stdout="_log.$BUILD_TAG.$name.stdout"
+       
+       rm -f "$log_stderr" "$log_stdout" 2>/dev/null
+}
+
+log_save_try ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: log_save_try <try>" >&2
+               exit 1
+       fi
+       
+       local try="$1"
+       local log_file
+       
+       ls "_log.$BUILD_TAG"* 2>/dev/null | while read log_file; do
+               if ! mv "$log_file" "$log_file-try-$try" 2>/dev/null; then
+                       echo "log_save_try: Unable to save log file $log_file to $log_file-try-$try"
+                       return 1
+               fi
+       done
+       return 0
+}
+
+run_tests ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: run_tests <tests directory>" >&2
+               exit 1
+       fi
+       
+       local test_dir="$1"
+       local entry
+       local test=()
+       local test_num=0
+       local test_iter=0
+       local test_path
+       local test_status
+       local test_failed=0
+       local test_start
+       local test_stop
+       local test_time
+       local pwd=`pwd`
+       local pwd2
+       local retry
+       local junit="$WORKSPACE/junit.xml"
+    local junit_head="$WORKSPACE/junit.xml.head"
+    local junit_test="$WORKSPACE/junit.xml.test"
+    local junit_foot="$WORKSPACE/junit.xml.foot"
+    local tail_pid
+    local test_name
+    local test_classname
+
+       if [ -n "$PRE_TEST" ]; then
+               if ! declare -F "$PRE_TEST" >/dev/null 2>/dev/null; then
+                       unset PRE_TEST
+               fi
+       fi
+       
+       if [ -n "$POST_TEST" ]; then
+               if ! declare -F "$POST_TEST" >/dev/null 2>/dev/null; then
+                       unset POST_TEST
+               fi
+       fi
+       
+    if [ -n "$INTERRUPT_TEST" ]; then
+        if ! declare -F "$INTERRUPT_TEST" >/dev/null 2>/dev/null; then
+            unset INTERRUPT_TEST
+        fi
+    fi
+    
+       if [ -n "$RETRY_TEST" ]; then
+               if [ ! "$RETRY_TEST" -gt 0 ] 2>/dev/null; then
+                       RETRY_TEST=0
+               fi
+       else
+               RETRY_TEST=0
+       fi
+
+       if [ -n "$RETRY_SLEEP" ]; then
+               if [ ! "$RETRY_SLEEP" -ge 0 ] 2>/dev/null; then
+                       RETRY_SLEEP=10
+               fi
+       else
+               RETRY_SLEEP=10
+       fi
+
+       if ! cd "$test_dir" 2>/dev/null; then
+               echo "run_tests: unable to change to test directory $test_dir!" >&2
+               return 1
+       fi
+               
+    rm -f "$junit" "$junit_test"
+    echo '<?xml version="1.0" encoding="UTF-8"?>' > "$junit_head"
+    echo '<testsuites>' > "$junit_head"
+
+       ls -1 2>/dev/null | $GREP '^[0-9]*' | $GREP -v '\.off$' 2>/dev/null >"_tests.$BUILD_TAG"
+       while read entry; do
+               if [ -d "$entry" -a -f "$entry/test.sh" ]; then
+                   if [ -f "$entry/off" ]; then
+                       test_name=`echo "$entry"|sed 's%\.% %g'|awk '{print $3}'`
+                       if [ -z "$test_name" ]; then
+                           test_name='unknown'
+                       fi
+                       test_classname=`echo "$entry"|sed 's%\.% %g'|awk '{print $1 "." $2}'`
+                       if [ -z "$test_classname" ]; then
+                           test_classname='unknown.unknown'
+                       fi
+                   echo '<testsuite name="'"$entry"'" tests="1" skip="1">' >> "$junit_test"
+                   echo '<testcase name="'"$test_name"'" classname="'"$test_classname"'">' >> "$junit_test"
+                echo '<skipped message="Skipped">Test skipped, disabled with off file</skipped>' >> "$junit_test"
+                   echo '</testcase>' >> "$junit_test"
+                   echo '</testsuite>' >> "$junit_test"
+               else
+                               test[test_num]="$entry"
+                               test_num=$(( test_num + 1 ))
+                       fi
+               fi
+       done <"_tests.$BUILD_TAG"
+       rm -f "_tests.$BUILD_TAG" 2>/dev/null
+       
+       if [ "$test_num" -le 0 ] 2>/dev/null; then
+               echo "run_tests: no active tests found!" >&2
+               cd "$pwd"
+               # Do not generate JUnit if there is no tests or all tests skipped because
+        # Jenkins might mark it failed otherwise
+           rm -f "$junit_head" "$junit_test" "$junit_foot"
+               return 1
+       fi
+       
+    if [ -n "$INTERRUPT_TEST" ]; then
+               STOP_TEST=0
+               trap "STOP_TEST=1" SIGINT
+       fi
+       
+       echo "Running tests ..."        
+       while [ "$test_iter" -lt "$test_num" ] 2>/dev/null; do
+               retry=0
+               test_path="${test[test_iter]}"
+               test_iter=$(( test_iter + 1 ))
+               test_start=`date +%s`
+        test_name=`echo "$test_path"|sed 's%\.% %g'|awk '{print $3}'`
+        if [ -z "$test_name" ]; then
+            test_name='unknown'
+        fi
+        test_classname=`echo "$test_path"|sed 's%\.% %g'|awk '{print $1 "." $2}'`
+        if [ -z "$test_classname" ]; then
+            test_classname='unknown.unknown'
+        fi
+               echo "##### `date` $test_iter/$test_num $test_path ... "
+               pwd2=`pwd`
+               cd "$test_path" 2>/dev/null &&
+               rm -f "_test.$BUILD_TAG" &&
+               touch "_test.$BUILD_TAG" &&
+               while [ "$retry" -le "$RETRY_TEST" ] 2>/dev/null; do
+                       if [ "$retry" -gt 0 ] 2>/dev/null; then
+                               syslog_stop &&
+                               log_save_try "$retry" &&
+                               syslog_save_try "$retry" ||
+                               {
+                                       echo "##### `date` $test_iter/$test_num $test_path ... Unable to retry"
+                                       test_status=1
+                                       break
+                               }
+                               echo "##### `date` $test_iter/$test_num $test_path ... RETRY $retry in $RETRY_SLEEP seconds"
+                               sleep "$RETRY_SLEEP"
+                rm -f "_test.$BUILD_TAG"
+                touch "_test.$BUILD_TAG"
+                       fi
+                       syslog_trace &&
+                       if [ -n "$PRE_TEST" ]; then
+                               $PRE_TEST "$test_path"
+                       fi &&
+                       ( source ./test.sh ) >> "_test.$BUILD_TAG" 2>&1
+            test_status="$?"
+                       if [ -n "$INTERRUPT_TEST" -a "$STOP_TEST" = "1" ]; then
+                cat "_test.$BUILD_TAG"
+                           echo "##### `date` $test_iter/$test_num $test_path ... INTERRUPTED"
+                           break
+                       fi
+                       if [ "$test_status" -eq 0 ] 2>/dev/null; then
+                               break
+                       fi
+                       retry=$(( retry + 1 ))
+               done
+               test_stop=`date +%s`
+               test_time=0
+        if [ "$test_start" -gt 0 -a "$test_stop" -gt 0 ] 2>/dev/null; then
+            test_time=$(( test_stop - test_start ))
+        fi
+               syslog_stop
+        if [ -n "$INTERRUPT_TEST" -a "$STOP_TEST" = "1" ]; then
+            $INTERRUPT_TEST "$test_path"
+            test_failed=1
+            break
+        elif [ -n "$POST_TEST" ]; then
+                       $POST_TEST "$test_path" "$test_status"
+               fi
+               if [ "$test_status" -eq 0 ] 2>/dev/null; then
+                       cat "_test.$BUILD_TAG"
+                       echo "##### `date` $test_iter/$test_num $test_path ... OK"
+                       log_cleanup
+                       syslog_cleanup
+
+            echo '<testsuite name="'"$test_path"'" tests="1" time="'"$test_time"'">' >> "$junit_test"
+               echo '<testcase name="'"$test_name"'" classname="'"$test_classname"'" time="'"$test_time"'">' >> "$junit_test"
+            echo '</testcase>' >> "$junit_test"
+            echo '<system-out>' >> "$junit_test"
+            cat "_test.$BUILD_TAG" | sed 's%&%\&amp;%g' | sed 's%<%\&lt;%g' | sed 's%>%\&gt;%g' >> "$junit_test" 2>/dev/null
+            echo '</system-out>' >> "$junit_test"
+            echo '</testsuite>' >> "$junit_test"
+               else
+                       test_failed=$(( test_failed + 1 ))
+            cat "_test.$BUILD_TAG"
+                       echo "##### `date` $test_iter/$test_num $test_path ... FAILED!"
+                       
+            echo '<testsuite name="'"$test_path"'" tests="1" time="'"$test_time"'">' >> "$junit_test"
+            echo '<testcase name="'"$test_name"'" classname="'"$test_classname"'" time="'"$test_time"'">' >> "$junit_test"
+            echo '<failure message="Failed">Test failed, exit code '"$test_status"'</failure>' >> "$junit_test"
+            echo '</testcase>' >> "$junit_test"
+            echo '<system-err>' >> "$junit_test"
+            cat "_test.$BUILD_TAG" | sed 's%&%\&amp;%g' | sed 's%<%\&lt;%g' | sed 's%>%\&gt;%g' >> "$junit_test" 2>/dev/null
+            echo '</system-err>' >> "$junit_test"
+            echo '</testsuite>' >> "$junit_test"
+               fi
+               rm -f "_test.$BUILD_TAG"
+
+               if ! cd "$pwd2" 2>/dev/null; then
+                       echo "run_tests: unable to change back to test directory $pwd2 after running a test!" >&2
+                       test_failed=1
+                       break
+               fi
+       done
+
+    if [ -n "$INTERRUPT_TEST" ]; then
+        trap "" SIGINT
+    fi
+
+    echo '</testsuites>' > "$junit_foot"
+    cat "$junit_head" "$junit_test" "$junit_foot" > "$junit" 2>/dev/null
+    rm -f "$junit_head" "$junit_test" "$junit_foot"
+
+       if ! cd "$pwd" 2>/dev/null; then
+               echo "run_tests: unable to change back to directory $pwd after running tests!" >&2
+               return 1
+       fi
+       
+       if [ "$test_failed" -gt 0 ] 2>/dev/null; then
+               return 1
+       fi
+}
+
+run_test ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: run_test <test name> <test directory>" >&2
+               exit 1
+       fi
+       
+       local test_name="$1"
+       local test_dir="$2"
+       local test_status
+       local pwd=`pwd`
+
+       if [ -n "$PRE_TEST" ]; then
+               if ! declare -F "$PRE_TEST" >/dev/null 2>/dev/null; then
+                       unset PRE_TEST
+               fi
+       fi
+
+       if [ -n "$POST_TEST" ]; then
+               if ! declare -F "$POST_TEST" >/dev/null 2>/dev/null; then
+                       unset POST_TEST
+               fi
+       fi
+
+    if [ -n "$INTERRUPT_TEST" ]; then
+        if ! declare -F "$INTERRUPT_TEST" >/dev/null 2>/dev/null; then
+            unset INTERRUPT_TEST
+        fi
+    fi
+       
+       if [ ! -f "$test_dir/test.sh" ]; then
+               echo "run_test: no test.sh in test $test_name ($test_dir)!" >&2
+               return 1
+       fi
+
+       if ! cd "$test_dir" 2>/dev/null; then
+               echo "run_test: unable to change to test $test_name directory $test_dir!" >&2
+               return 1
+       fi
+
+    if [ -n "$INTERRUPT_TEST" ]; then
+        STOP_TEST=0
+        trap "STOP_TEST=1" SIGINT
+    fi
+
+       echo "##### Running test $test_name ..." 
+       if [ -n "$PRE_TEST" ]; then
+               $PRE_TEST "$test_name"
+       fi &&
+       syslog_trace &&
+       ( source ./test.sh )
+       test_status="$?"
+       syslog_stop
+    if [ -n "$INTERRUPT_TEST" -a "$STOP_TEST" = "1" ]; then
+        echo "##### `date` $test_iter/$test_num $test_path ... INTERRUPTED"
+           $INTERRUPT_TEST "$test_path"
+           trap "" SIGINT
+           return 1
+    elif [ -n "$POST_TEST" ]; then
+               $POST_TEST "$test_name" "$test_status"
+       fi
+       if [ "$test_status" -eq 0 ] 2>/dev/null; then
+               echo "##### Test $test_name ... OK" 
+               log_cleanup
+               syslog_cleanup
+       else
+               echo "##### Test $test_name ... FAILED!" 
+       fi
+
+       if ! cd "$pwd" 2>/dev/null; then
+               echo "run_test: unable to change back to directory $pwd after running test $test_name!" >&2
+               return 1
+       fi
+       
+       if [ "$test_status" -ne 0 ] 2>/dev/null; then
+               return 1
+       fi
+}
+
+syslog_trace ()
+{
+       if [ -n "$_SYSLOG_TRACE_PID" ]; then
+               echo "syslog_trace: Syslog trace already running (pid $_SYSLOG_TRACE_PID)!" >&2
+               exit 1
+       fi
+
+       local syslog_file
+       
+       case "$DISTRIBUTION" in
+               debian | \
+               ubuntu )
+                       syslog_file="/var/log/syslog"
+                       ;;
+               redhat | \
+               centos | \
+               sl | \
+               slackware | \
+               opensuse | \
+               suse | \
+               freebsd | \
+               netbsd | \
+               openbsd )
+                       syslog_file="/var/log/messages"
+                       ;;
+               sunos )
+                       syslog_file="/var/adm/messages"
+                       ;;
+       esac
+
+       if [ -z "$syslog_file" ]; then
+               echo "syslog_trace: Unable to start trace of syslog: no syslog file set" >&2
+               exit 1
+       fi
+
+       if [ ! -r "$syslog_file" ]; then
+               echo "syslog_trace: Unable to start trace of syslog: no access to $syslog_file" >&2
+               exit 1
+       fi
+
+       $TAIL_FOLLOW "$syslog_file" >"_syslog.$BUILD_TAG" 2>/dev/null &
+       _SYSLOG_TRACE_PID="$!"
+       
+       if [ -z "$_SYSLOG_TRACE_PID" -o ! "$_SYSLOG_TRACE_PID" -gt 0 ] 2>/dev/null; then
+               echo "syslog_trace: Unable to start trace of syslog!" >&2
+               exit 1
+       fi
+
+       if ! kill -0 "$_SYSLOG_TRACE_PID" 2>/dev/null >/dev/null; then
+               wait "$_SYSLOG_TRACE_PID"
+               echo "syslog_trace: Unable to start trace of syslog: exited with status $?"
+               exit 1
+       fi
+       
+       echo "syslog_trace: trace started (pid $_SYSLOG_TRACE_PID)"
+}
+
+syslog_stop ()
+{
+       if [ -z "$_SYSLOG_TRACE_PID" ]; then
+               echo "syslog_stop: Syslog trace not started!" >&2
+               exit 1
+       fi
+       
+       if kill -TERM "$_SYSLOG_TRACE_PID" 2>/dev/null; then
+               wait "$_SYSLOG_TRACE_PID" 2>/dev/null
+               unset _SYSLOG_TRACE_PID
+       fi
+       
+       if [ -n "$_SYSLOG_TRACE_PID" ]; then
+               echo "syslog_stop: Unable to stop trace of syslog!" >&2
+               exit 1
+       fi
+       
+       echo "syslog_stop: trace stopped"
+}
+
+syslog_waitfor ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: syslog_waitfor <timeout in seconds> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local timeout="$1"
+       local grep_string="$2"
+               
+       if [ ! -f "_syslog.$BUILD_TAG" ]; then
+               echo "syslog_waitfor: No syslog file to grep from!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "syslog_waitfor: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "syslog_waitfor: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "syslog_waitfor: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       echo "syslog_waitfor: waiting for syslog to contain (timeout $timeout): $grep_string"
+       while true; do
+               if $GREP -q -- "$grep_string" "_syslog.$BUILD_TAG" 2>/dev/null; then
+                       return 0
+               fi
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ -z "$_SYSLOG_TRACE_PID" -o "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "syslog_waitfor: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               sleep 2
+       done
+       
+       return 1
+}
+
+syslog_waitfor_count ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: syslog_waitfor_count <timeout in seconds> <count> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local timeout="$1"
+       local count="$2"
+       local grep_string="$3"
+       local count_found
+               
+       if [ ! -f "_syslog.$BUILD_TAG" ]; then
+               echo "syslog_waitfor_count: No syslog file to grep from!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "syslog_waitfor_count: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "syslog_waitfor_count: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "syslog_waitfor_count: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       echo "syslog_waitfor_count: waiting for syslog to contain $count counts of (timeout $timeout): $grep_string"
+       while true; do
+               count_found=`$GREP -- "$grep_string" "_syslog.$BUILD_TAG" 2>/dev/null | wc -l 2>/dev/null`
+               if [ "$count_found" -eq "$count" ] 2>/dev/null; then
+                       return 0
+               fi
+
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ -z "$_SYSLOG_TRACE_PID" -o "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "syslog_waitfor_count: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               sleep 2
+       done
+       
+       return 1
+}
+
+syslog_grep ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: syslog_grep <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local grep_string="$1"
+       
+       if [ ! -f "_syslog.$BUILD_TAG" ]; then
+               echo "syslog_grep: No syslog file to grep from!" >&2
+               exit 1
+       fi
+
+       echo "syslog_grep: greping syslog for: $grep_string"
+       $GREP -q -- "$grep_string" "_syslog.$BUILD_TAG" 2>/dev/null
+}
+
+syslog_grep_count ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: syslog_grep_count <count> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local count="$1"
+       local grep_string="$2"
+       local count_found
+       # create a non-local variable so the caller can get the actually value if they want
+       syslog_grep_count_variable=0
+       
+       if [ ! -f "_syslog.$BUILD_TAG" ]; then
+               echo "syslog_grep_count: No syslog file to grep from!" >&2
+               exit 1
+       fi
+
+       echo "syslog_grep_count: greping syslog, should find $count of: $grep_string"
+       count_found=`$GREP -- "$grep_string" "_syslog.$BUILD_TAG" 2>/dev/null | wc -l 2>/dev/null`
+       syslog_grep_count_variable=$count_found
+       
+       if [ "$count_found" -eq "$count" ] 2>/dev/null; then
+               return 0
+       fi
+       
+       return 1
+}
+
+syslog_cleanup ()
+{
+       rm -f "_syslog.$BUILD_TAG"* 2>/dev/null
+}
+
+syslog_save_try ()
+{
+       if [ -z "$1" ]; then
+               echo "usage: syslog_save_try <try>" >&2
+               exit 1
+       fi
+       
+       local try="$1"
+
+       if ! mv "_syslog.$BUILD_TAG" "_syslog.$BUILD_TAG-try-$try" 2>/dev/null; then
+               echo "syslog_save_try: Unable to save syslog file _syslog.$BUILD_TAG to _syslog.$BUILD_TAG-try-$try"
+               return 1
+       fi
+       return 0
+}
+
+apply_parameter ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: apply_parameter <parameter tag> <parameter value> <files ... >" >&2
+               echo "   ex: apply_parameter \"INSTALL_ROOT\" \"\$INSTALL_ROOT\" conf.xml" >&2
+               exit 1
+       fi
+       
+       local parameter_tag="$1"
+       local parameter_value="$2"
+       shift 2
+       local files="$*"
+       local file
+       
+       if echo "$parameter_tag" | grep -q "@" 2>/dev/null; then
+               echo "apply_parameter: parameter tag contains '@', it must not" >&2
+               return 1
+       fi
+       
+       for file in $files; do
+               if [ ! -f "$file" ]; then
+                       echo "apply_parameter: File $file not found" >&2
+                       return 1
+               fi
+               if [ -f "$file.$$" ]; then
+                       echo "apply_parameter: Temporary file $file.$$ exists but it should not" >&2
+                       return 1
+               fi
+       done
+       
+       for file in $files; do
+               sed 's%@'"$parameter_tag"'@%'"$parameter_value"'%g' "$file" > "$file.$$" 2>/dev/null &&
+               mv "$file.$$" "$file" 2>/dev/null ||
+               {
+                       echo "apply_parameter: Unable to apply parameter $parameter_tag value $parameter_value to file $file" >&2
+                       return 1
+               }
+       done
+       
+       return 0
+}
+
+sed_inplace ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: sed_inplace <expression> <files ... >" >&2
+               exit 1
+       fi
+       
+       local expression="$1"
+       shift 1
+       local files="$*"
+       local file
+       
+       for file in $files; do
+               if [ ! -f "$file" ]; then
+                       echo "sed_inplace: File $file not found" >&2
+                       return 1
+               fi
+               if [ -f "$file.$$" ]; then
+                       echo "sed_inplace: Temporary file $file.$$ exists but it should not" >&2
+                       return 1
+               fi
+       done
+       
+       for file in $files; do
+               sed "$expression" "$file" > "$file.$$" 2>/dev/null &&
+               mv "$file.$$" "$file" 2>/dev/null ||
+               {
+                       echo "sed_inplace: Unable to sed inplace file $file" >&2
+                       return 1
+               }
+       done
+       
+       return 0
+}
+
+try_run ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: try_run <timeout in seconds> <command ... >" >&2
+               exit 1
+       fi
+       
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local timeout="$1"
+       local pid
+       shift
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "try_run: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "try_run: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "try_run: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       ( $* ) &
+       pid="$!"
+       
+       if [ -z "$pid" -o "$pid" -le 0 ] 2>/dev/null; then
+               echo "try_run: No pid from backgrounded program?" >&2
+               return 1
+       fi
+       
+       while true; do
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "try_run: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               if ! kill -0 "$pid" 2>/dev/null; then
+                       wait "$pid"
+                       return "$?"
+               fi
+               sleep 1
+       done
+
+       kill -TERM "$pid"
+       sleep 1
+       if kill -0 "$pid" 2>/dev/null; then
+               kill -KILL "$pid"
+       fi      
+       return 1
+}
+
+waitfor_this ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: waitfor_this <file to grep> <timeout in seconds> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local file="$1"
+       local timeout="$2"
+       local grep_string="$3"
+               
+       if [ ! -f "$file" ]; then
+               echo "waitfor_this: No file to grep from!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "waitfor_this: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "waitfor_this: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "waitfor_this: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       echo "waitfor_this: waiting for $file to contain (timeout $timeout): $grep_string"
+       while true; do
+               if $GREP -q -- "$grep_string" "$file" 2>/dev/null; then
+                       return 0
+               fi
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "waitfor_this: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               sleep 2
+       done
+       
+       return 1
+}
+
+waitfor_count_this ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ]; then
+               echo "usage: waitfor_count_this <file to grep> <timeout in seconds> <count> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local time_start=`$DATE '+%s' 2>/dev/null`
+       local time_stop
+       local time_now
+       local file="$1"
+       local timeout="$2"
+       local count="$3"
+       local grep_string="$4"
+       local count_found
+               
+       if [ ! -f "$file" ]; then
+               echo "waitfor_count_this: No file to grep from!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$time_start" -gt 0 ] 2>/dev/null; then
+               echo "waitfor_count_this: Unable to get start time!" >&2
+               exit 1
+       fi
+       
+       if [ ! "$timeout" -gt 0 ] 2>/dev/null; then
+               echo "waitfor_count_this: Wrong timeout value or 0!" >&2
+               exit 1
+       fi
+       
+       if [ "$timeout" -gt 3600 ] 2>/dev/null; then
+               echo "waitfor_count_this: Too long timeout used, can't be over 3600 seconds!" >&2
+               exit 1
+       fi
+       
+       time_stop=$(( time_start + timeout ))
+
+       echo "waitfor_count_this: waiting for $file to contain $count counts of (timeout $timeout): $grep_string"
+       while true; do
+               count_found=`$GREP -- "$grep_string" "$file" 2>/dev/null | wc -l 2>/dev/null`
+               if [ "$count_found" -eq "$count" ] 2>/dev/null; then
+                       return 0
+               fi
+
+               time_now=`$DATE '+%s' 2>/dev/null`
+               if [ "$time_now" -ge "$time_stop" ] 2>/dev/null; then
+                       break
+               fi
+               if [ -z "$time_now" -o ! "$time_now" -lt "$time_stop" ] 2>/dev/null; then
+                       echo "waitfor_count_this: Invalid timestamp from date!" >&2
+                       exit 1
+               fi
+               sleep 2
+       done
+       
+       return 1
+}
+
+grep_this ()
+{
+       if [ -z "$1" -o -z "$2" ]; then
+               echo "usage: grep_this <file to grep> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local file="$1"
+       local grep_string="$2"
+       
+       if [ ! -f "$file" ]; then
+               echo "grep_this: No file to grep from!" >&2
+               exit 1
+       fi
+
+       echo "grep_this: greping in $file for: $grep_string"
+       $GREP -q -- "$grep_string" "$file" 2>/dev/null
+}
+
+grep_count_this ()
+{
+       if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+               echo "usage: grep_count_this <file to grep> <count> <grep string ...>" >&2
+               exit 1
+       fi
+       
+       local file="$1"
+       local count="$2"
+       local grep_string="$3"
+       local count_found
+       
+       if [ ! -f "$file" ]; then
+               echo "grep_count_this: No file to grep from!" >&2
+               exit 1
+       fi
+
+       echo "grep_count_this: greping in $file, should find $count of: $grep_string"
+       count_found=`$GREP -- "$grep_string" "$file" 2>/dev/null | wc -l 2>/dev/null`
+       
+       if [ "$count_found" -eq "$count" ] 2>/dev/null; then
+               return 0
+       fi
+       
+       return 1
+}
diff --git a/SoftHSMv2/testing/travis/travis.sh b/SoftHSMv2/testing/travis/travis.sh
new file mode 100644 (file)
index 0000000..6a1ca1f
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+CONF_CRYPTO=""
+CONF_OBJSTORE=""
+
+case $CRYPTO in
+botan)
+       CONF_CRYPTO="$CONF_CRYPTO --with-crypto-backend=botan --with-botan=/usr"
+       CONF_CRYPTO="$CONF_CRYPTO --disable-ecc --disable-gost"
+       ;;
+openssl)
+       CONF_CRYPTO="$CONF_CRYPTO --with-crypto-backend=openssl --with-openssl=/usr"
+       CONF_CRYPTO="$CONF_CRYPTO --disable-gost"
+       openssl version -a
+       ;;
+*)
+       echo "Unknown crypto backend"
+       exit 1
+esac
+
+case $OBJSTORE in
+file)
+       CONF_OBJSTORE="$CONF_OBJSTORE"
+       ;;
+sqlite)
+       CONF_OBJSTORE="$CONF_OBJSTORE --with-objectstore-backend-db --with-migrate"
+       ;;
+*)
+       echo "Unknown objectstore backend"
+       exit 1
+esac
+
+sh autogen.sh && \
+./configure $CONF_CRYPTO $CONF_OBJSTORE && \
+make all check
diff --git a/SoftHSMv2/win32/.gitignore b/SoftHSMv2/win32/.gitignore
new file mode 100644 (file)
index 0000000..997db95
--- /dev/null
@@ -0,0 +1,35 @@
+# get back config.h.in
+!config.h.in
+
+# Visual Studio
+*.opensdf
+*.sdf
+*.suo
+.vs/
+
+# Object files
+*.obj
+*.exe
+
+# Generated project files
+convarch.vcxproj
+convarch.vcxproj.filters
+cryptotest.vcxproj
+datamgrtest.vcxproj
+dump.vcxproj
+handlemgrtest.vcxproj
+keyconv.vcxproj
+keyconv.vcxproj.filters
+objstoretest.vcxproj
+p11test.vcxproj
+sessionmgrtest.vcxproj
+slotmgrtest.vcxproj
+softhsm2.vcxproj
+softhsm2.sln
+util.vcxproj
+util.vcxproj.filters
+
+# Build files
+Debug/
+Release/
+x64/
\ No newline at end of file
diff --git a/SoftHSMv2/win32/Configure.py b/SoftHSMv2/win32/Configure.py
new file mode 100644 (file)
index 0000000..a39a046
--- /dev/null
@@ -0,0 +1,1167 @@
+#!python
+
+# Configure -- python version
+#
+# this script builds Visual Studio files
+
+from __future__ import print_function
+
+import sys
+import os
+import os.path
+import re
+import subprocess
+
+# files to configure
+
+filelist = ["config.h",
+            "softhsm2.sln",
+            "convarch\\convarch.vcxproj.filters",
+            "convarch\\convarch.vcxproj",
+            "cryptotest\\cryptotest.vcxproj",
+            "datamgrtest\\datamgrtest.vcxproj",
+            "dump\\dump.vcxproj",
+            "handlemgrtest\\handlemgrtest.vcxproj",
+            "keyconv\\keyconv.vcxproj.filters",
+            "keyconv\\keyconv.vcxproj",
+            "objstoretest\\objstoretest.vcxproj",
+            "p11test\\p11test.vcxproj",
+            "sessionmgrtest\\sessionmgrtest.vcxproj",
+            "slotmgrtest\\slotmgrtest.vcxproj",
+            "softhsm2\\softhsm2.vcxproj",
+            "util\\util.vcxproj.filters",
+            "util\\util.vcxproj"]
+
+# test files
+testlist = ["botan",
+            "ecc",
+            "gnump",
+            "gost",
+            "ossl",
+            "osslv",
+            "rawpss",
+            "rfc3394",
+            "rfc5649"]
+
+# variables to expand
+
+varvals = {}
+
+varnames = ["CUINCPATH",
+            "CULIBPATH",
+            "DEBUGDLLPATH",
+            "DEBUGINCPATH",
+            "DEBUGLIBPATH",
+            "DLLPATH",
+            "EXTRALIBS",
+            "INCLUDEPATH",
+            "LIBNAME",
+            "LIBPATH",
+            "PLATFORM",
+            "PLATFORMDIR",
+            "PLATFORMTOOLSET",
+            "RUNTIMELIBRARY"]
+
+# conditions to stack
+
+condvals = {}
+
+condnames = ["AESGCM",
+             "BOTAN",
+             "ECC",
+             "GOST",
+             "NONPAGE",
+             "OPENSSL",
+             "RAWPSS",
+             "RFC3394",
+             "RFC5649",
+             "TESTS"]
+
+# enable-xxx/disable-xxx arguments
+
+enablelist = ["64bit",
+              "debug",
+              "ecc",
+              "gost",
+              "keep",
+              "non-paged-memory",
+              "static-runtime",
+              "verbose"]
+
+# with-xxx/without-xxx arguments
+
+withlist = ["botan",
+            "cppunit",
+            "crypto-backend",
+            "debug-botan",
+            "debug-openssl",
+            "openssl",
+            "toolset"]
+
+# general commands
+
+commandlist = ["help", "clean"] # verbose, keep
+
+# usage
+
+usage = ["Usage: python Configure.py help",
+         "       python Configure.py options*",
+         "       python Configure.py clean"]
+
+# help
+
+myhelp = ["'python Configure.py' configures SoftHSMv2 build files.\n"] +\
+usage + [\
+"\nGeneral Commands:",
+"  help                     print this help",
+"  clean                    clean up generated files",
+"  <none>                   print a summary of the configuration",
+"\nOptional Features:",
+"  enable-verbose           print messages [default=no]",
+"  enable-keep              keep test files after config [default=no]",
+"  enable-64bit             enable 64-bit compiling [default=no]",
+"  enable-debug             enable build of Debug config [default=yes]",
+"  enable-ecc               enable support for ECC [default=yes]",
+"  enable-gost              enable support for GOST [default=yes]",
+"  enable-static-runtime    enable build with static CRT (/MT) [default=no]",
+"  enable-non-paged-memory  enable non-paged memory [default=yes]",
+"\nOptional Packages:",
+"  with-crypto-backend      select the crypto backend [openssl|botan]",
+"  with-botan=PATH          speficy prefix of path of Botan (Release)",
+"  with-debug-botan=PATH    speficy prefix of path of Botan (Debug)",
+"  with-openssl=PATH        speficy prefix of path of OpenSSL (Release)",
+"  with-debug-openssl=PATH  speficy prefix of path of OpenSSL (Debug)",
+"  with-cppunit=PATH        specify prefix of path of CppUnit",
+"  with-toolset=VALUE       set Visual Studio platform toolset version (eg v110 for vs2012)",
+]
+
+# variables for parsing
+
+verbose = False
+configargs = None
+want_help = False
+want_clean = False
+want_unknown = False
+unknown_value = None
+enable_keep = False
+enable_debug = True
+enable_ecc = True
+enable_gost = True
+enable_static_runtime = False
+enable_non_paged = True
+platform = 32
+crypto_backend = "openssl"
+botan_path = "..\\..\\btn"
+debug_botan_path = None
+openssl_path = "..\\..\\ssl"
+debug_openssl_path = None
+want_tests = True
+cppunit_path = "..\\..\\cu"
+toolset = ""
+
+def dodetectplatform(visualstudio):
+    # detect platform tool set >= VS2010
+    global toolset
+
+    if "Microsoft Visual Studio 10.0" in visualstudio:
+        toolset="v100"
+    elif "Microsoft Visual Studio 11.0" in visualstudio:
+        toolset="v110"
+    elif "Microsoft Visual Studio 12.0" in visualstudio:
+        toolset="v120"
+    elif "Microsoft Visual Studio 14.0" in visualstudio:
+        toolset="v140"
+    else:
+        print("PlatformToolset for \""+visualstudio+"\" not supported")
+        toolset=""
+
+def dodetectvisualstudio():
+    """detect visual studio version"""
+    if os.environ.get('VSINSTALLDIR'):
+        dodetectplatform(os.environ.get('VSINSTALLDIR'))
+
+def parseargs(args):
+    """parse arguments"""
+    global verbose
+    global enable_keep
+    global want_help
+    global want_clean
+    global want_unknown
+    global unknown_value
+    global debug_botan_path
+    global debug_openssl_path
+    for arg in args:
+        if arg.lower() == "verbose":
+            verbose = True
+            continue
+        if arg.lower() == "keep":
+            enable_keep = True
+            continue
+        if arg.lower() == "help":
+            want_help = True
+            continue
+        di = re.match(r'disable-(.*)', arg, re.I)
+        if di:
+            appargs(arg)
+            myenable(di.group(1), False)
+            continue
+        en = re.match(r'enable-(.*)', arg, re.I)
+        if en:
+            appargs(arg)
+            myenable(en.group(1), True)
+            continue
+        wo = re.match(r'without-(.*)', arg, re.I)
+        if wo:
+            appargs(arg)
+            mywith(wo.group(1), False)
+            continue
+        wv = re.match(r'with-(.*)=(.*)', arg, re.I)
+        if wv:
+            appargs(arg)
+            if wv.group(2).lower() == "no":
+                mywith(wv.group(1), False)
+                continue
+            mywith(wv.group(1), True, wv.group(2))
+            continue
+        wi = re.match(r'with-(.*)', arg, re.I)
+        if wi:
+            appargs(arg)
+            mywith(wi.group(1), True)
+            continue
+        if arg.lower() == "clean":
+            want_clean = True
+            continue
+        want_unknown = True
+        unknown_value = arg
+        break
+
+    # debug
+    if enable_debug:
+        if debug_botan_path is None:
+            debug_botan_path = botan_path + "_d"
+        if debug_openssl_path is None:
+            debug_openssl_path = openssl_path + "_d"
+
+def appargs(arg):
+    """append seen arguments to configargs"""
+    global configargs
+    # escape backslashes, spaces and double quotes
+    escaped = ""
+
+    for x in arg:
+        if (x == "\\") or (x == " ") or (x == "\""):
+            escaped += "\\"
+        escaped += x
+    if configargs:
+        configargs += " " + escaped
+    else:
+        configargs = escaped
+
+def myenable(key, val):
+    """parse enable/disable"""
+    global platform
+    global enable_debug
+    global enable_ecc
+    global enable_gost
+    global enable_static_runtime
+    global enable_non_paged
+    global enable_keep
+    global verbose
+    global want_unknown
+    global unknown_value
+    if key.lower() == "64bit":
+        if val:
+            platform = 64
+        return
+    if key.lower() == "debug":
+        if not val:
+            enable_debug = False
+        return
+    if key.lower() == "ecc":
+        if not val:
+            enable_ecc = False
+        return
+    if key.lower() == "gost":
+        if not val:
+            enable_gost = False
+        return
+    if key.lower() == "static-runtime":
+        if val:
+            enable_static_runtime = True
+        return
+    if key.lower() == "non-paged-memory":
+        if not val:
+            enable_non_paged = False
+        return
+    if key.lower() == "keep":
+        if val:
+            enable_keep = True
+        return
+    if key.lower() == "verbose":
+        if val:
+            verbose = True
+        return
+    want_unknown = True
+    if not val:
+        unknown_value = "disable-" + key
+    else:
+        unknown_value = "enable-" + key
+
+def mywith(key, val, detail=None):
+    """parse with/without"""
+    global crypto_backend
+    global botan_path
+    global debug_botan_path
+    global openssl_path
+    global debug_openssl_path
+    global want_tests
+    global cppunit_path
+    global want_unknown
+    global unknown_value
+    global toolset
+
+    if key.lower() == "crypto-backend":
+        if val and (detail.lower() == "openssl"):
+            crypto_backend = "openssl"
+            return
+        if val and (detail.lower() == "botan"):
+            crypto_backend = "botan"
+            return
+        want_unknown = True
+        unknown_value = "with-crypto-backend=" + detail
+        return
+    if key.lower() == "botan":
+        if not val:
+            want_unknown = True
+            unknown_value = "without-botan doesn't make sense"
+            return
+        if detail.lower() != "yes":
+            botan_path = detail
+        return
+    if key.lower() == "debug-botan":
+        if not val:
+            want_unknown = True
+            unknown_value = "without-debug-botan doesn't make sense"
+            return
+        if detail.lower() != "yes":
+            debug_botan_path = detail
+        return
+    if key.lower() == "openssl":
+        if not val:
+            want_unknown = True
+            unknown_value = "without-openssl doesn't make sense"
+            return
+        if detail.lower() != "yes":
+            openssl_path = detail
+        return
+    if key.lower() == "debug-openssl":
+        if not val:
+            want_unknown = True
+            unknown_value = "without-debug-openssl doesn't make sense"
+            return
+        if detail.lower() != "yes":
+            debug_openssl_path = detail
+        return
+    if key.lower() == "cppunit":
+        if not val:
+            want_tests = False
+            return
+        if detail.lower() != "yes":
+            cppunit_path = detail
+        return
+    if key.lower() == "toolset":
+        if not val:
+            want_tests = False
+            return
+        if detail:
+            toolset=detail.lower()
+        return
+    want_unknown = True
+    if not val:
+        unknown_value = "without-" + key
+    else:
+        unknown_value = "with-" + key
+
+def dohelp():
+    """help"""
+    for line in myhelp:
+        print(line)
+    sys.exit(1)
+
+def docleantest():
+    """clean test files"""
+    for basename in testlist:
+        filename = "test" + basename + ".c"
+        if os.path.isfile(filename):
+            os.unlink(filename)
+        filename = "test" + basename + ".cpp"
+        if os.path.isfile(filename):
+            os.unlink(filename)
+        filename = "test" + basename + ".obj"
+        if os.path.isfile(filename):
+            os.unlink(filename)
+        filename = "test" + basename + ".exe"
+        if os.path.isfile(filename):
+            os.unlink(filename)
+    if os.path.isfile("botan.dll"):
+        os.unlink("botan.dll")
+    if os.path.isfile("libeay32.dll"):
+        os.unlink("libeay32.dll")
+    if os.path.isfile("libeaycompat32.dll"):
+        os.unlink("libeaycompat32.dll")
+    if os.path.isfile("libcrypto-1_1.dll"):
+        os.unlink("libcrypto-1_1.dll")
+    if os.path.isfile("libcrypto-1_1-x64.dll"):
+        os.unlink("libcrypto-1_1-x64.dll")
+
+def doclean():
+    """clean"""
+    docleantest()
+    for filename in filelist:
+        if os.path.isfile(filename):
+            os.unlink(filename)
+    sys.exit(0)
+
+def dounknown():
+    """parsing error"""
+    print("can't parse " + unknown_value + "", file=sys.stderr)
+    sys.exit(1)
+
+def doconfig():
+    """config itself"""
+    global botan_path
+    global debug_botan_path
+    global openssl_path
+    global debug_openssl_path
+    global cppunit_path
+
+    # configure the platform
+    if platform == 32:
+        varvals["PLATFORM"] = "Win32"
+    else:
+        varvals["PLATFORM"] = "x64"
+        varvals["PLATFORMDIR"] = "x64\\"
+
+    # configure the runtime library
+    if enable_static_runtime:
+        varvals["RUNTIMELIBRARY"] = "MultiThreaded"
+    else:
+        varvals["RUNTIMELIBRARY"] = "MultiThreadedDLL"
+
+    # configure ECC and GOST
+    if enable_ecc:
+        condvals["ECC"] = True
+    if enable_gost:
+        condvals["GOST"] = True
+
+    # configure the crypto
+    if crypto_backend == "botan":
+        condvals["BOTAN"] = True
+        varvals["LIBNAME"] = "botan.lib"
+        botan_path = os.path.abspath(botan_path)
+        botan_inc = os.path.join(botan_path, "include")
+        botan_dll = ""
+        if os.path.exists(os.path.join(botan_inc, "botan-2\\botan\\init.h")):
+            varvals["INCLUDEPATH"] = os.path.join(botan_inc, "botan-2")
+        elif os.path.exists(os.path.join(botan_inc, "botan-1.11\\botan\\init.h")):
+            varvals["INCLUDEPATH"] = os.path.join(botan_inc, "botan-1.11")
+        elif os.path.exists(os.path.join(botan_inc, "botan\\init.h")):
+            varvals["INCLUDEPATH"] = botan_inc
+        else:
+            print("can't find Botan includes", file=sys.stderr)
+            sys.exit(1)
+        if os.path.exists(os.path.join(botan_path, "lib\\botan.lib")):
+            varvals["LIBPATH"] = os.path.join(botan_path, "lib")
+            botan_dll = os.path.join(botan_path, "lib\\botan.dll")
+        elif os.path.exists(os.path.join(botan_path, "botan.lib")):
+            varvals["LIBPATH"] = botan_path
+            botan_dll = os.path.join(botan_path, "botan.dll")
+        else:
+            print("can't find Botan library", file=sys.stderr)
+            sys.exit(1)
+        varvals["DLLPATH"] = botan_dll
+        if enable_debug:
+            debug_botan_path = os.path.abspath(debug_botan_path)
+            debug_botan_inc = os.path.join(debug_botan_path, "include")
+            debug_botan_dll = ""
+            if os.path.exists(os.path.join(debug_botan_inc, "botan-2\\botan\\init.h")):
+                varvals["DEBUGINCPATH"] = os.path.join(debug_botan_inc, "botan-2")
+            elif os.path.exists(os.path.join(debug_botan_inc, "botan-1.11\\botan\\init.h")):
+                varvals["DEBUGINCPATH"] = os.path.join(debug_botan_inc, "botan-1.11")
+            elif os.path.exists(os.path.join(debug_botan_inc, "botan\\init.h")):
+                varvals["DEBUGINCPATH"] = debug_botan_inc
+            else:
+                print("can't find debug Botan includes", file=sys.stderr)
+                sys.exit(1)
+            if os.path.exists(os.path.join(debug_botan_path, "lib\\botan.lib")):
+                varvals["DEBUGLIBPATH"] = os.path.join(debug_botan_path, "lib")
+                debug_botan_dll = os.path.join(debug_botan_path, "lib\\botan.dll")
+            if os.path.exists(os.path.join(debug_botan_path, "botan.lib")):
+                varvals["DEBUGLIBPATH"] = debug_botan_path
+                debug_botan_dll = os.path.join(debug_botan_path, "botan.dll")
+            else:
+                print("can't find debug Botan library", file=sys.stderr)
+                sys.exit(1)
+            varvals["DEBUGDLLPATH"] = debug_botan_dll
+        else:
+            varvals["DEBUGDLLPATH"] = varvals["DLLPATH"]
+            varvals["DEBUGINCPATH"] = varvals["INCLUDEPATH"]
+            varvals["DEBUGLIBPATH"] = varvals["LIBPATH"]
+
+        # Botan version
+        if verbose:
+            print("checking Botan version")
+        botan_version_major = 0
+        botan_version_minor = 0
+        system_libs = []
+        if os.path.exists(botan_dll):
+            subprocess.call(["copy", botan_dll, "."], shell=True)
+        else:
+            system_libs = ["user32.lib", "advapi32.lib"]
+        inc = varvals["INCLUDEPATH"]
+        lib = os.path.join(varvals["LIBPATH"], "botan.lib")
+        testfile = open("testbotan.cpp", "w")
+        print('\
+#include <botan/version.h>\n\
+int main() {\n\
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0)\n\
+ return 3;\n\
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)\n\
+ return 2;\n\
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)\n\
+ return 1;\n\
+#else\n\
+ return 0;\n\
+#endif\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testbotan.cpp", lib]
+        command.extend(system_libs)
+        subprocess.check_output(command, stderr=subprocess.STDOUT)
+        if not os.path.exists(".\\testbotan.exe"):
+            print("can't create .\\testbotan.exe", file=sys.stderr)
+            sys.exit(1)
+        ret = subprocess.call(".\\testbotan.exe")
+        if ret == 0:
+            print("Botan version too old", file=sys.stderr)
+            sys.exit(1)
+        elif ret == 1:
+            botan_version_major = 1
+            botan_version_minor = 10
+        elif ret == 2:
+            botan_version_major = 1
+            botan_version_minor = 11
+            print("Botan version 1.11 not yet supported", file=sys.stderr)
+            sys.exit(1)
+        elif ret == 3:
+            botan_version_major = 2
+            botan_version_minor = 0
+            print("Botan version 2.0 not yet supported", file=sys.stderr)
+            sys.exit(1)
+        else:
+            print("Botan test failed", file=sys.stderr)
+            sys.exit(1)
+
+        # Botan ECC support
+        if enable_ecc:
+            if verbose:
+                print("checking Botan ECC support")
+            testfile = open("testecc.cpp", "w")
+            print('\
+#include <botan/init.h>\n\
+#include <botan/ec_group.h>\n\
+#include <botan/oids.h>\n\
+#include <botan/version.h>\n\
+int main() {\n\
+ Botan::LibraryInitializer::initialize();\n\
+ const std::string name("secp256r1");\n\
+ const Botan::OID oid(Botan::OIDS::lookup(name));\n\
+ const Botan::EC_Group ecg(oid);\n\
+ try {\n\
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)\n\
+  const std::vector<Botan::byte> der =\n\
+   ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);\n\
+#else\n\
+  const Botan::SecureVector<Botan::byte> der =\n\
+   ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);\n\
+#endif\n\
+ } catch(...) {\n\
+  return 1;\n\
+ }\n\
+ return 0;\n\
+}', file=testfile)
+            testfile.close()
+            command = ["cl", "/nologo", "/MD", "/I", inc, "testecc.cpp", lib]
+            command.extend(system_libs)
+            subprocess.check_output(command, stderr=subprocess.STDOUT)
+            if not os.path.exists(".\\testecc.exe"):
+                print("can't create .\\testecc.exe", file=sys.stderr)
+                sys.exit(1)
+            if subprocess.call(".\\testecc.exe") != 0:
+                print("can't find P256: upgrade to Botan >= 1.10.6", file=sys.stderr)
+                sys.exit(1)
+
+        # Botan GOST support
+        if enable_gost:
+            if verbose:
+                print("checking Botan GOST support")
+            testfile = open("testgost.cpp", "w")
+            print('\
+#include <botan/init.h>\n\
+#include <botan/gost_3410.h>\n\
+#include <botan/oids.h>\n\
+#include <botan/version.h>\n\
+int main() {\n\
+ Botan::LibraryInitializer::initialize();\n\
+ const std::string name("gost_256A");\n\
+ const Botan::OID oid(Botan::OIDS::lookup(name));\n\
+ const Botan::EC_Group ecg(oid);\n\
+ try {\n\
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)\n\
+  const std::vector<Botan::byte> der =\n\
+   ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);\n\
+#else\n\
+  const Botan::SecureVector<Botan::byte> der =\n\
+   ecg.DER_encode(Botan::EC_DOMPAR_ENC_OID);\n\
+#endif\n\
+ } catch(...) {\n\
+  return 1;\n\
+ }\n\
+ return 0;\n\
+}', file=testfile)
+            testfile.close()
+            command = ["cl", "/nologo", "/MD", "/I", inc, "testgost.cpp", lib]
+            command.extend(system_libs)
+            subprocess.check_output(command, stderr=subprocess.STDOUT)
+            if not os.path.exists(".\\testgost.exe"):
+                print("can't create .\\testgost.exe", file=sys.stderr)
+                sys.exit(1)
+            if subprocess.call(".\\testgost.exe") != 0:
+                print("can't find GOST: upgrade to Botan >= 1.10.6", file=sys.stderr)
+                sys.exit(1)
+
+        # no check for Botan RFC3394 support
+        condvals["RFC3394"] = True
+
+        # Botan RFC5649 support
+        if verbose:
+            print("checking Botan RFC5649 support")
+        testfile = open("testrfc5649.cpp", "w")
+        print('\
+#include <botan/botan.h>\n\
+#include <botan/rfc3394.h>\n\
+#include <botan/version.h>\n\
+using namespace Botan;\n\
+int main() {\n\
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)\n\
+ secure_vector<byte> key(10);\n\
+ SymmetricKey kek("AABB");\n\
+ secure_vector<byte> x = rfc5649_keywrap(key, kek);\n\
+#else\n\
+ SecureVector<byte> key(10);\n\
+ SymmetricKey kek("AABB");\n\
+ Algorithm_Factory& af = global_state().algorithm_factory();\n\
+ SecureVector<byte> x = rfc5649_keywrap(key, kek, af);\n\
+#endif\n\
+ return 1;\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/EHsc","/I", inc, "testrfc5649.cpp", lib]
+        command.extend(system_libs)
+        subprocess.call(command)
+        if os.path.exists(".\\testrfc5649.exe"):
+            if verbose:
+                print("Found AES key wrap with pad")
+            condvals["RFC5649"] = True
+        else:
+            if verbose:
+                print("can't compile Botan AES key wrap with pad")
+
+        # Botan GNU MP support
+        if botan_version_major == 1 and botan_version_minor == 10:
+            if verbose:
+                print("checking Botan GNU MP support")
+            testfile = open("testgnump.cpp", "w")
+            print('\
+#include <botan/build.h>\n\
+int main() {\n\
+#ifndef BOTAN_HAS_ENGINE_GNU_MP\n\
+#error "No GNU MP support";\n\
+#endif\n\
+}', file=testfile)
+            testfile.close()
+            command = ["cl", "/nologo", "/MD", "/I", inc, "testgnump.cpp", lib]
+            command.extend(system_libs)
+            subprocess.call(command)
+            if os.path.exists(".\\testgnump.exe"):
+                if verbose:
+                    print("Botan GNU MP is supported")
+            else:
+                if verbose:
+                    print("Botan GNU MP is not supported")
+
+        # Botan raw PSS support
+        if verbose:
+            print("checking Botan raw PSS support")
+        testfile = open("testrawpss.cpp", "w")
+        print('\
+#include <botan/botan.h>\n\
+#include <botan/version.h>\n\
+int main() {\n\
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,3,0)\n\
+ return 0;\n\
+#endif\n\
+ return 1;\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testrawpss.cpp", lib]
+        command.extend(system_libs)
+        subprocess.check_output(command, stderr=subprocess.STDOUT)
+        if not os.path.exists(".\\testrawpss.exe"):
+            if verbose:
+                print("can't create .\\testrawpss.exe", file=sys.stderr)
+        else:
+            if subprocess.call(".\\testrawpss.exe") != 0:
+                if verbose:
+                    print("can't find raw PSS: upgrade to Botan >= 2.3.0", file=sys.stderr)
+            else:
+                condvals["RAWPSS"] = True
+
+    else:
+
+        condvals["OPENSSL"] = True
+        varvals["EXTRALIBS"] = "crypt32.lib;ws2_32.lib;"
+        openssl_path = os.path.abspath(openssl_path)
+        openssl_inc = os.path.join(openssl_path, "include")
+        if not os.path.exists(os.path.join(openssl_inc, "openssl\\ssl.h")):
+            print("can't find OpenSSL headers", file=sys.stderr)
+            sys.exit(1)
+        varvals["INCLUDEPATH"] = openssl_inc
+        openssl_lib = os.path.join(openssl_path, "lib")
+        openssl_lib_name = ""
+        openssl_lib_dll = ""
+        if os.path.exists(os.path.join(openssl_lib, "libeay32.lib")):
+            openssl_lib_name = "libeay32.lib"
+            openssl_lib_dll = "bin\\libeay32.dll"
+        elif os.path.exists(os.path.join(openssl_lib, "libeaycompat32.lib")):
+            openssl_lib_name = "libeaycompat32.lib"
+            openssl_lib_dll = "bin\\libeaycompat32.dll"
+        elif os.path.exists(os.path.join(openssl_lib, "libcrypto.lib")):
+            openssl_lib_name = "libcrypto.lib"
+            if platform == 32:
+                openssl_lib_dll = "bin\\libcrypto-1_1.dll"
+            else:
+                openssl_lib_dll = "bin\\libcrypto-1_1-x64.dll"
+
+        else:
+            print("can't find OpenSSL library", file=sys.stderr)
+            sys.exit(1)
+        openssl_dll = os.path.join(openssl_path,openssl_lib_dll)
+        varvals["LIBPATH"] = openssl_lib
+        varvals["LIBNAME"] = openssl_lib_name
+        varvals["DLLPATH"] = openssl_dll
+        if enable_debug:
+            debug_openssl_path = os.path.abspath(debug_openssl_path)
+            varvals["DEBUGDLLPATH"] = \
+                os.path.join(debug_openssl_path, openssl_lib_dll)
+            debug_openssl_inc = os.path.join(debug_openssl_path, "include")
+            if not os.path.exists(os.path.join(debug_openssl_inc,
+                                               "openssl\\ssl.h")):
+                print("can't find debug OpenSSL headers", file=sys.stderr)
+                sys.exit(1)
+            varvals["DEBUGINCPATH"] = debug_openssl_inc
+            debug_openssl_lib = os.path.join(debug_openssl_path, "lib")
+            if not os.path.exists(os.path.join(debug_openssl_lib,
+                                               openssl_lib_name)):
+                print("can't find debug OpenSSL library", file=sys.stderr)
+                sys.exit(1)
+            varvals["DEBUGLIBPATH"] = debug_openssl_lib
+        else:
+            varvals["DEBUGDLLPATH"] = varvals["DLLPATH"]
+            varvals["DEBUGINCPATH"] = varvals["INCLUDEPATH"]
+            varvals["DEBUGLIBPATH"] = varvals["LIBPATH"]
+
+        # OpenSSL support
+        if verbose:
+            print("checking OpenSSL")
+        system_libs = []
+        if os.path.exists(openssl_dll):
+            subprocess.call(["copy", openssl_dll, "."], shell=True)
+        else:
+            system_libs = ["user32.lib", "advapi32.lib", "gdi32.lib", "crypt32.lib", "ws2_32.lib"]
+        inc = openssl_inc
+        lib = os.path.join(openssl_lib, openssl_lib_name)
+        testfile = open("testossl.c", "w")
+        print('\
+#include <openssl/err.h>\n\
+int main() {\n\
+ ERR_clear_error();\n\
+ return 0;\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testossl.c", lib]
+        command.extend(system_libs)
+        subprocess.check_output(command, stderr=subprocess.STDOUT)
+        if not os.path.exists(".\\testossl.exe"):
+            print("can't create .\\testossl.exe", file=sys.stderr)
+            sys.exit(1)
+        if subprocess.call(".\\testossl.exe") != 0:
+            print("OpenSSL test failed", file=sys.stderr)
+            sys.exit(1)
+
+        # OpenSSL version
+        if verbose:
+            print("checking OpenSSL version")
+        testfile = open("testosslv.c", "w")
+        print('\
+#include <openssl/ssl.h>\n\
+#include <openssl/opensslv.h>\n\
+int main() {\n\
+#ifndef OPENSSL_VERSION_NUMBER\n\
+ return -1;\n\
+#endif\n\
+#if OPENSSL_VERSION_NUMBER >= 0x010000000L\n\
+ return 0;\n\
+#else\n\
+ return 1;\n\
+#endif\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testosslv.c", lib]
+        command.extend(system_libs)
+        subprocess.check_output(command, stderr=subprocess.STDOUT)
+        if not os.path.exists(".\\testosslv.exe"):
+            print("can't create .\\testosslv.exe", file=sys.stderr)
+            sys.exit(1)
+        if subprocess.call(".\\testosslv.exe") != 0:
+            print("OpenSLL version too old (1.0.0 or later required)", file=sys.stderr)
+            sys.exit(1)
+
+        # OpenSSL ECC support
+        if enable_ecc:
+            if verbose:
+                print("checking OpenSSL ECC support")
+            testfile = open("testecc.c", "w")
+            print('\
+#include <openssl/ecdsa.h>\n\
+#include <openssl/objects.h>\n\
+int main() {\n\
+ EC_KEY *ec256, *ec384, *ec521;\n\
+ ec256 = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);\n\
+ ec384 = EC_KEY_new_by_curve_name(NID_secp384r1);\n\
+ ec521 = EC_KEY_new_by_curve_name(NID_secp521r1);\n\
+ if (ec256 == NULL || ec384 == NULL || ec521 == NULL)\n\
+  return 1;\n\
+ return 0;\n\
+}', file=testfile)
+            testfile.close()
+            command = ["cl", "/nologo", "/MD", "/I", inc, "testecc.c", lib]
+            command.extend(system_libs)
+            subprocess.check_output(command, stderr=subprocess.STDOUT)
+            if not os.path.exists(".\\testecc.exe"):
+                print("can't create .\\testecc.exe", file=sys.stderr)
+                sys.exit(1)
+            if subprocess.call(".\\testecc.exe") != 0:
+                print("can't find P256, P384, or P521: no ECC support", file=sys.stderr)
+                sys.exit(1)
+
+        # OpenSSL GOST support
+        if enable_gost:
+            if verbose:
+                print("checking OpenSSL GOST support")
+            testfile = open("testgost.c", "w")
+            print('\
+#include <openssl/conf.h>\n\
+#include <openssl/engine.h>\n\
+#include <openssl/crypto.h>\n\
+#include <openssl/opensslv.h>\n\
+int main() {\n\
+ ENGINE *eg;\n\
+ const EVP_MD* EVP_GOST_34_11;\n\
+ OpenSSL_add_all_algorithms();\n\
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)\n\
+ ENGINE_load_builtin_engines();\n\
+#else\n\
+ OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN | OPENSSL_INIT_LOAD_CONFIG, NULL);\n\
+#endif\n\
+ eg = ENGINE_by_id("gost");\n\
+ if (eg == NULL)\n\
+  return 1;\n\
+ if (ENGINE_init(eg) <= 0)\n\
+  return 1;\n\
+ EVP_GOST_34_11 = ENGINE_get_digest(eg, NID_id_GostR3411_94);\n\
+ if (EVP_GOST_34_11 == NULL)\n\
+  return 1;\n\
+ if (ENGINE_register_pkey_asn1_meths(eg) <= 0)\n\
+  return 1;\n\
+ if (ENGINE_ctrl_cmd_string(eg, "CRYPT_PARAMS",\n\
+     "id-Gost28147-89-CryptoPro-A-ParamSet", 0) <= 0)\n\
+  return 1;\n\
+ return 0;\n\
+}', file=testfile)
+            testfile.close()
+            command = ["cl", "/nologo", "/MD", "/I", inc, "testgost.c", lib]
+            command.extend(system_libs)
+            subprocess.check_output(command, stderr=subprocess.STDOUT)
+            if not os.path.exists(".\\testgost.exe"):
+                print("can't create .\\testgost.exe", file=sys.stderr)
+                sys.exit(1)
+            if subprocess.call(".\\testgost.exe") != 0:
+                print("can't find GOST: no GOST support", file=sys.stderr)
+                sys.exit(1)
+
+        # OpenSSL EVP interface for AES key wrapping (aka RFC 3394)
+        if verbose:
+            print("checking OpenSSL EVP interface for AES key wrapping")
+        testfile = open("testrfc3394.c", "w")
+        print('\
+#include <openssl/evp.h>\n\
+int main() {\n\
+ EVP_aes_128_wrap();\n\
+ return 1;\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testrfc3394.c", lib]
+        command.extend(system_libs)
+        subprocess.call(command)
+        if os.path.exists(".\\testrfc3394.exe"):
+            if verbose:
+                print("RFC 3394 is supported")
+            condvals["RFC3394"] = True
+        else:
+            if verbose:
+                print("can't compile OpenSSL RFC 3394")
+
+        # OpenSSL EVP interface for AES key wrap with pad (aka RFC 5649)
+        if verbose:
+            print("checking OpenSSL EVP interface for AES key wrapping with pad")
+        testfile = open("testrfc5649.c", "w")
+        print('\
+#include <openssl/evp.h>\n\
+int main() {\n\
+ EVP_aes_128_wrap_pad();\n\
+ return 1;\n\
+}', file=testfile)
+        testfile.close()
+        command = ["cl", "/nologo", "/MD", "/I", inc, "testrfc5649.c", lib]
+        command.extend(system_libs)
+        subprocess.call(command)
+        if os.path.exists(".\\testrfc5649.exe"):
+            if verbose:
+                print("RFC 5649 is supported")
+            condvals["RFC5649"] = True
+        else:
+            if verbose:
+                print("can't compile OpenSSL RFC 5649")
+
+        # no check for OpenSSL raw PSS support
+        condvals["RAWPSS"] = True
+        # no check for OpenSSL AES GCM
+        condvals["AESGCM"] = True
+
+    # configure CppUnit
+    if want_tests:
+        condvals["TESTS"] = True
+        cppunit_path = os.path.abspath(cppunit_path)
+        cppunit_inc = os.path.join(cppunit_path, "include")
+        if not os.path.exists(os.path.join(cppunit_inc, "cppunit\\Test.h")):
+            print("can't find CppUnit headers", file=sys.stderr)
+            sys.exit(1)
+        varvals["CUINCPATH"] = cppunit_inc
+        cppunit_lib = os.path.join(cppunit_path, "lib")
+        if not os.path.exists(os.path.join(cppunit_lib, "cppunit.lib")):
+            cppunit_lib = cppunit_path
+        if not os.path.exists(os.path.join(cppunit_lib, "cppunit.lib")):
+            print("can't find CppUnit library", file=sys.stderr)
+            sys.exit(1)
+        if enable_debug:
+            if not os.path.exists(os.path.join(cppunit_lib, "cppunitd.lib")):
+                print("can't find debug CppUnit library", file=sys.stderr)
+                sys.exit(1)
+        varvals["CULIBPATH"] = cppunit_lib
+
+    # misc
+    if enable_non_paged:
+        condvals["NONPAGE"] = True
+
+def kw(path):
+    """escape spaces"""
+    if re.search(r' ', path):
+        return '"' + path + '"'
+    else:
+        return path
+
+def setupfile(filename):
+    """setup files with condition stacks and variable expansions"""
+    cond = "@@@"
+    conds = []
+    passing = True
+    passes = []
+    filein = open(filename + ".in", "r")
+    fileout = open(filename, "w")
+
+    for line in filein:
+        line = line.rstrip("\r\n")
+        cif = re.match(r'@IF (.*)', line)
+        if cif:
+            conds.append(cond)
+            passes.append(passing)
+            cond = cif.group(1)
+            if condvals.get(cond):
+                # do nothing
+                pass
+            else:
+                passing = False
+            continue
+        celse = re.match(r'@ELSE (.*)', line)
+        if celse:
+            if cond != celse.group(1):
+                raise SyntaxError("@ELSE " + celse.group(1) +
+                                  " mismatch in " + filename)
+            if condvals.get(cond):
+                passing = False
+            else:
+                if len(passes) > 0:
+                    passing = passes[-1]
+                else:
+                    passing = True
+            continue
+        cend = re.match(r'@END (.*)', line)
+        if cend:
+            if cond != cend.group(1):
+                raise SyntaxError("@END " + cend.group(1) +
+                                  " mismatch in " + filename)
+            cond = conds.pop()
+            if len(passes) > 0:
+                passing = passes.pop()
+            else:
+                passing = True
+            continue
+        if not passing:
+            continue
+        while True:
+            vm = re.match(r'([^@]*)@([^@ ]*)@(.*)', line)
+            if vm:
+                if vm.group(2) in varnames:
+                    if varvals.get(vm.group(2)):
+                        val = kw(varvals[vm.group(2)])
+                    else:
+                        val = ""
+                    line = vm.group(1) + val + vm.group(3)
+                    continue
+                else:
+                    raise SyntaxError("unknown control @" + vm.group(2) +
+                                      "@ in " + filename)
+            break
+        print(line, file=fileout)
+    if verbose:
+        print("Setting up " + filename)
+    filein.close()
+    fileout.close()
+
+def main(args):
+    """run it"""
+
+    # no arguments -> usage
+    if len(args) <= 1:
+        for line in usage:
+            print(line)
+        sys.exit(1)
+
+    parseargs(args[1:])
+
+    if want_help:
+        dohelp()
+    if want_clean:
+        doclean()
+    if want_unknown:
+        dounknown()
+    if not toolset:
+        dodetectvisualstudio()
+    if not toolset:
+        print("Build skipped. To build, this file needs to run from VS command prompt.")
+        sys.exit(1)
+
+    varvals["PLATFORMTOOLSET"] = toolset
+
+    # status before config
+    if verbose:
+        if enable_keep:
+            print("keep: enabled")
+        else:
+            print("keep: disabled")
+        if platform == 64:
+            print("64bit: enabled")
+        else:
+            print("64bit: disabled")
+        if enable_debug:
+            print("debug: enabled")
+        else:
+            print("debug: disabled")
+        if enable_ecc:
+            print("ecc: enabled")
+        else:
+            print("ecc: disabled")
+        if enable_gost:
+            print("gost: enabled")
+        else:
+            print("gost: disabled")
+        if enable_non_paged:
+            print("non-paged-memory: enabled")
+        else:
+            print("non-paged-memory: disabled")
+        print("crypto-backend: " + crypto_backend)
+        if crypto_backend == "botan":
+            print("botan-path: " + botan_path)
+            if enable_debug:
+                print("debug-botan-path: " + debug_botan_path)
+        else:
+            print("openssl-path: " + openssl_path)
+            if enable_debug:
+                print("debug-openssl-path: " + debug_openssl_path)
+        if want_tests:
+            print("cppunit-path: " + cppunit_path)
+        print("toolset: "+toolset)
+
+
+    doconfig()
+
+    # status after config
+    if verbose:
+        print("Configuration Status")
+        print("\tconditions:")
+        for name in condnames:
+            if condvals.get(name):
+                print("\t\t" + name + " is true")
+            else:
+                print("\t\t" + name + " is false")
+        print("\tsubstitutions:")
+        for name in varnames:
+            if varvals.get(name):
+                print("\t\t" + name + '-> "' + varvals[name] + '"')
+        print()
+
+    for filename in filelist:
+        setupfile(filename)
+
+    # clean test file
+    if not enable_keep:
+        docleantest()
+
+    print("Configured.")
+    sys.exit(0)
+
+main(sys.argv)
+
+# Notes: Unix configure.ac options
+#  --enable-64bit supported
+#  --enable-ecc supported
+#  --enable-gost supported
+#  --enable-non-paged-memory supported
+#  --enable-visibility (enforced by DLLs)
+#  --with-crypto-backend supported
+#  --with-botan supported (Release and Debug)
+#  --with-openssl supported (Release and Debug)
+#  --with-migrate (useless as SoftHSMv1 is not supported)
+#  --with-objectstore-backend-db (TODO)
+#  --with-sqlite3 (useless until objectstore backend can be chosen)
diff --git a/SoftHSMv2/win32/config.h.in b/SoftHSMv2/win32/config.h.in
new file mode 100644 (file)
index 0000000..f2b56ba
--- /dev/null
@@ -0,0 +1,185 @@
+/* config.h for WIN32 */
+
+/* The default log level */
+#define DEFAULT_LOG_LEVEL "INFO"
+
+/* Default storage backend for token objects */
+#define DEFAULT_OBJECTSTORE_BACKEND "file"
+
+/* The default PKCS#11 library */
+#define DEFAULT_PKCS11_LIB "softhsm2.dll"
+
+/* The default location of softhsm2.conf */
+#define DEFAULT_SOFTHSM2_CONF "softhsm2.conf"
+
+/* The default location of the token directory */
+#define DEFAULT_TOKENDIR "tokens"
+
+/* Define if advanced AES key wrap without pad is supported */
+@IF RFC3394
+#define HAVE_AES_KEY_WRAP 1
+@ELSE RFC3394
+#undef HAVE_AES_KEY_WRAP
+@END RFC3394
+
+/* Define if advanced AES key wrap with pad is supported */
+@IF RFC5649
+#define HAVE_AES_KEY_WRAP_PAD 1
+@ELSE RFC5649
+#undef HAVE_AES_KEY_WRAP_PAD
+@END RFC5649
+
+/* Whether LoadLibrary is available */
+#define HAVE_LOADLIBRARY 1
+
+/* Define to 1 if you have the <sqlite3.h> header file. */
+#undef HAVE_SQLITE3_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Maximum PIN length */
+#define MAX_PIN_LEN 255
+
+/* Minimum PIN length */
+#define MIN_PIN_LEN 4
+
+/* Name of package */
+#define PACKAGE "softhsm"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "SoftHSM"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "SoftHSM 2.3.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "softhsm"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION  "2.3.0"
+
+/* Non-paged memory for secure storage */
+@IF NONPAGE
+#define SENSITIVE_NON_PAGE 1
+@ELSE NONPAGE
+#undef SENSITIVE_NON_PAGE
+@END NONPAGE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#define VERSION  "2.3.0"
+
+/* SoftHSM major version number via PKCS#11 */
+#define VERSION_MAJOR 2
+
+/* SoftHSM minor version number via PKCS#11 */
+#define VERSION_MINOR 3
+
+/* Compile with Botan support */
+@IF BOTAN
+#define WITH_BOTAN 1
+@ELSE BOTAN
+#undef WITH_BOTAN
+@END BOTAN
+
+/* Compile with ECC support */
+@IF ECC
+#define WITH_ECC 1
+@ELSE ECC
+#undef WITH_ECC
+@END ECC
+
+/* Compile with GOST support */
+@IF GOST
+#define WITH_GOST 1
+@ELSE GOST
+#undef WITH_GOST
+@END GOST
+
+/* Compile with OpenSSL support */
+@IF OPENSSL
+#define WITH_OPENSSL 1
+@ELSE OPENSSL
+#undef WITH_OPENSSL
+@END OPENSSL
+
+/* Compile with raw PSS support */
+@IF RAWPSS
+#define WITH_RAW_PSS 1
+@ELSE RAWPSS
+#undef WITH_RAW_PSS
+@END RAWPSS
+
+/* Compile with AES GCM support */
+@IF AESGCM
+#define WITH_AES_GCM 1
+@ELSE AESGCM
+#undef WITH_AES_GCM
+@END AESGCM
+
+/* Define to 1 if you have getpassphrase(). */
+#define HAVE_GETPASSPHRASE
+
+/* Addition things */
+
+char *getpassphrase(const char *prompt);
+int setenv(const char *name, const char *value, int overwrite);
+
+/* At least Vista */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif
+
+#if _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+
+/* Prevent inclusion of winsock.h in windows.h */
+
+#define WIN32_LEAN_AND_MEAN 1
+
+#include <windows.h>
+
+/* avoid collision from min and max macros */
+
+#undef min
+#undef max
+
+@IF BOTAN
+/* For Botan */
+
+#pragma warning(disable: 4275 4267)
+@END BOTAN
+
+/* Temporary for debug */
+
+#undef DEBUG_LOG_STDERR
+// #define DEBUG_LOG_STDERR 1
+
+/* To avoid unsafe warnings (off) */
+
+// #pragma warning(disable: 4996)
diff --git a/SoftHSMv2/win32/convarch/convarch.vcxproj.filters.in b/SoftHSMv2/win32/convarch/convarch.vcxproj.filters.in
new file mode 100644 (file)
index 0000000..d3c84f1
--- /dev/null
@@ -0,0 +1,928 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Header Files">\r
+      <UniqueIdentifier>{b657b1af-4cc4-4d97-ba6a-0a7231c5f243}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Source Files">\r
+      <UniqueIdentifier>{aacfc93a-d2e0-4935-aa15-ea0d3690fbcd}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Crypto Header Files">\r
+      <UniqueIdentifier>{6337c51f-53e3-440a-9ab9-40f0b9a4f26e}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Crypto Source Files">\r
+      <UniqueIdentifier>{8566a5d1-d688-41da-bbc3-3d860f2db764}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Data Mgr Header Files">\r
+      <UniqueIdentifier>{b427db7b-49c3-47b0-982a-7da01cf39c8e}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Data Mgr Source Files">\r
+      <UniqueIdentifier>{04a46825-a433-4b5c-9c3f-8c489978cb8a}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Handle Mgr Header Files">\r
+      <UniqueIdentifier>{9e67afe5-3252-4c46-a24f-096e4a35e174}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Handle Mgr Source Files">\r
+      <UniqueIdentifier>{b8a7e894-ebbe-43de-ad66-3c45d91aac8e}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Object Store Header Files">\r
+      <UniqueIdentifier>{0c47956d-aa5e-4c26-bee4-63ec89c0ab64}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Object Store Source Files">\r
+      <UniqueIdentifier>{45c69303-5073-4bde-8b63-2f2e2a688362}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Session Mgr Header Files">\r
+      <UniqueIdentifier>{d1a8b25d-8ebb-4a79-ae8c-70ef3c0bed5f}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Session Mgr Source Files">\r
+      <UniqueIdentifier>{cb379241-3d4b-4f7c-b7d1-c6c83d3a1b62}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Slot Mgr Header Files">\r
+      <UniqueIdentifier>{5420eba7-6b85-4daf-a916-c85421362984}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Slot Mgr Source Files">\r
+      <UniqueIdentifier>{3c9f55a5-d1a8-4716-a416-ec172a676e63}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Source Files">\r
+      <UniqueIdentifier>{63e3d8a2-0853-4f98-bcaa-de05da380d37}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Header Files">\r
+      <UniqueIdentifier>{59b2221a-36a3-4f2c-9883-6173599baf5a}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\common\Configuration.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\fatal.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\HandleFactory.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\log.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\MutexFactory.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\osmutex.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\Serialisable.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\SimpleConfigLoader.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\AESKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricParameters.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+@IF BOTAN\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanAES.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanCryptoFactory.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDES.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDH.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSA.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDH.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSA.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOST.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTR3411.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanHashAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMAC.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMacAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMD5.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRNG.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSA.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAKeyPair.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA1.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA224.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA256.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA384.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA512.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSymmetricAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanUtil.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\Botan_ecb.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\Botan_rounding.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+@END BOTAN\r
+    <ClInclude Include="..\..\src\lib\crypto\CryptoFactory.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DESKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DHParameters.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DHPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DHPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAParameters.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\ECParameters.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\ECPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\ECPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\GOSTPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\GOSTPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\HashAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\MacAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\odd.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+@IF OPENSSL\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLAES.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLCryptoFactory.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDES.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDH.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHKeyPair.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHPrivateKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAPrivateKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHPublicKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSA.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAKeyPair.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAPublicKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECDH.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECDSA.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECKeyPair.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECPrivateKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECPublicKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPHashAlgorithm.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPCMacAlgorithm.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPMacAlgorithm.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPSymmetricAlgorithm.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOST.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTKeyPair.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTPrivateKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTPublicKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTR3411.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLCMAC.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLHMAC.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLMD5.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRNG.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSA.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAKeyPair.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAPrivateKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAPublicKey.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA1.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA224.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA256.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA384.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA512.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLUtil.h">\r
+       <Filter>Crypto Header Files</Filter>\r
+     </ClInclude>\r
+@END OPENSSL\r
+    <ClInclude Include="..\..\src\lib\crypto\PrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\PublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\RNG.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAParameters.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAPrivateKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAPublicKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\SymmetricAlgorithm.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\SymmetricKey.h">\r
+      <Filter>Crypto Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\ByteString.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\RFC4880.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\salloc.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureAllocator.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureMemoryRegistry.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureDataManager.h">\r
+      <Filter>Data Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\Handle.h">\r
+      <Filter>Handle Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\HandleManager.h">\r
+      <Filter>Handle Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\Directory.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\File.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\FindOperation.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\Generation.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectFile.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectStore.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectStoreToken.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\OSAttribute.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\OSAttributes.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\OSObject.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\OSPathSep.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\OSToken.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\SessionObject.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\SessionObjectStore.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\UUID.h">\r
+      <Filter>Object Store Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\session_mgr\Session.h">\r
+      <Filter>Session Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\session_mgr\SessionManager.h">\r
+      <Filter>Session Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\Slot.h">\r
+      <Filter>Slot Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\SlotManager.h">\r
+      <Filter>Slot Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\Token.h">\r
+      <Filter>Slot Mgr Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\win32\syslog.h">\r
+      <Filter>Win32 Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\common\Configuration.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\fatal.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\log.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\MutexFactory.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\osmutex.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\SimpleConfigLoader.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\AsymmetricAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\AsymmetricKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanAES.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanCryptoFactory.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDES.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDH.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSA.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDH.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSA.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOST.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTR3411.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanHashAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMAC.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMacAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMD5.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRNG.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSA.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAKeyPair.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA1.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA224.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA256.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA384.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA512.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSymmetricAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanUtil.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\Botan_ecb.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+@END BOTAN\r
+    <ClCompile Include="..\..\src\lib\crypto\CryptoFactory.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DESKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DHParameters.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DHPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DHPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAParameters.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\ECParameters.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\ECPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\ECPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\GOSTPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\GOSTPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\HashAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\MacAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+@IF OPENSSL\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLAES.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLCryptoFactory.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDES.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDH.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHKeyPair.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHPrivateKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHPublicKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSA.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAKeyPair.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAPrivateKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAPublicKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECDH.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECDSA.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECKeyPair.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECPrivateKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECPublicKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPHashAlgorithm.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPCMacAlgorithm.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPMacAlgorithm.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPSymmetricAlgorithm.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOST.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTKeyPair.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTPrivateKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTPublicKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTR3411.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLCMAC.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLHMAC.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLMD5.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRNG.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSA.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAKeyPair.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAPrivateKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAPublicKey.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA1.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA224.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA256.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA384.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA512.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLUtil.cpp">\r
+       <Filter>Crypto Source Files</Filter>\r
+     </ClCompile>\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAParameters.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAPrivateKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAPublicKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\SymmetricAlgorithm.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\SymmetricKey.cpp">\r
+      <Filter>Crypto Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\ByteString.cpp">\r
+      <Filter>Data Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\RFC4880.cpp">\r
+      <Filter>Data Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\salloc.cpp">\r
+      <Filter>Data Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\SecureDataManager.cpp">\r
+      <Filter>Data Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\SecureMemoryRegistry.cpp">\r
+      <Filter>Data Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\Handle.cpp">\r
+      <Filter>Handle Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\HandleManager.cpp">\r
+      <Filter>Handle Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\Directory.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\File.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\FindOperation.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\Generation.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectFile.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectStore.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectStoreToken.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\OSAttribute.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\OSToken.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\SessionObject.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\SessionObjectStore.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\UUID.cpp">\r
+      <Filter>Object Store Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\session_mgr\Session.cpp">\r
+      <Filter>Session Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\session_mgr\SessionManager.cpp">\r
+      <Filter>Session Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\Slot.cpp">\r
+      <Filter>Slot Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\SlotManager.cpp">\r
+      <Filter>Slot Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\Token.cpp">\r
+      <Filter>Slot Mgr Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\win32\syslog.cpp">\r
+      <Filter>Win32 Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/convarch/convarch.vcxproj.in b/SoftHSMv2/win32/convarch/convarch.vcxproj.in
new file mode 100644 (file)
index 0000000..b711f35
--- /dev/null
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\common\Configuration.h" />\r
+    <ClInclude Include="..\..\src\lib\common\fatal.h" />\r
+    <ClInclude Include="..\..\src\lib\common\HandleFactory.h" />\r
+    <ClInclude Include="..\..\src\lib\common\log.h" />\r
+    <ClInclude Include="..\..\src\lib\common\MutexFactory.h" />\r
+    <ClInclude Include="..\..\src\lib\common\osmutex.h" />\r
+    <ClInclude Include="..\..\src\lib\common\Serialisable.h" />\r
+    <ClInclude Include="..\..\src\lib\common\SimpleConfigLoader.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\AESKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\AsymmetricParameters.h" />\r
+@IF BOTAN\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanAES.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanCryptoFactory.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDES.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDH.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDHPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSA.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanDSAPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDH.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDHPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSA.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanECDSAPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOST.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanGOSTR3411.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanHashAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMAC.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMacAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanMD5.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRNG.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSA.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAKeyPair.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanRSAPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA1.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA224.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA256.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA384.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSHA512.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanSymmetricAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\BotanUtil.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\Botan_ecb.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\Botan_rounding.h" />\r
+@END BOTAN\r
+    <ClInclude Include="..\..\src\lib\crypto\CryptoFactory.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DESKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DHParameters.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DHPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DHPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAParameters.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\DSAPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\ECParameters.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\ECPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\ECPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\GOSTPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\GOSTPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\HashAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\MacAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\odd.h" />\r
+@IF OPENSSL\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLAES.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLCryptoFactory.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDES.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDH.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHKeyPair.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHPrivateKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDHPublicKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSA.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAKeyPair.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAPrivateKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLDSAPublicKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECDH.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECDSA.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECKeyPair.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECPrivateKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLECPublicKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPHashAlgorithm.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPCMacAlgorithm.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPMacAlgorithm.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLEVPSymmetricAlgorithm.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOST.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTKeyPair.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTPrivateKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTPublicKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLGOSTR3411.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLCMAC.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLHMAC.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLMD5.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRNG.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSA.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAKeyPair.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAPrivateKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLRSAPublicKey.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA1.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA224.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA256.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA384.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLSHA512.h" />\r
+     <ClInclude Include="..\..\src\lib\crypto\OSSLUtil.h" />\r
+@END OPENSSL\r
+    <ClInclude Include="..\..\src\lib\crypto\PrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\PublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\RNG.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAParameters.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAPrivateKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\RSAPublicKey.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\SymmetricAlgorithm.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\SymmetricKey.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\ByteString.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\RFC4880.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\salloc.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureAllocator.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureDataManager.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\SecureMemoryRegistry.h" />\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\Handle.h" />\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\HandleManager.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\Directory.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\File.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\FindOperation.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\Generation.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectFile.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectStore.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\ObjectStoreToken.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\OSAttribute.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\OSAttributes.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\OSObject.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\OSPathSep.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\OSToken.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\SessionObject.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\SessionObjectStore.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\UUID.h" />\r
+    <ClInclude Include="..\..\src\lib\session_mgr\Session.h" />\r
+    <ClInclude Include="..\..\src\lib\session_mgr\SessionManager.h" />\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\Slot.h" />\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\SlotManager.h" />\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\Token.h" />\r
+    <ClInclude Include="..\..\src\lib\win32\syslog.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\common\Configuration.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\fatal.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\log.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\MutexFactory.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\osmutex.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\SimpleConfigLoader.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\AESKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\AsymmetricAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\AsymmetricKeyPair.cpp" />\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanAES.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanCryptoFactory.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDES.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDH.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDHPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSA.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanDSAPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDH.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDHPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSA.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanECDSAPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOST.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanGOSTR3411.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanHashAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMAC.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMacAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanMD5.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRNG.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSA.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAKeyPair.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanRSAPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA1.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA224.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA256.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA384.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSHA512.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanSymmetricAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\BotanUtil.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\Botan_ecb.cpp" />\r
+@END BOTAN\r
+    <ClCompile Include="..\..\src\lib\crypto\CryptoFactory.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DESKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DHParameters.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DHPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DHPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAParameters.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\DSAPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\ECParameters.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\ECPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\ECPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\GOSTPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\GOSTPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\HashAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\MacAlgorithm.cpp" />\r
+@IF OPENSSL\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLAES.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLCryptoFactory.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDES.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDH.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHKeyPair.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHPrivateKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDHPublicKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSA.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAKeyPair.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAPrivateKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLDSAPublicKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECDH.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECDSA.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECKeyPair.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECPrivateKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLECPublicKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPHashAlgorithm.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPCMacAlgorithm.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPMacAlgorithm.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLEVPSymmetricAlgorithm.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOST.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTKeyPair.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTPrivateKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTPublicKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLGOSTR3411.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLCMAC.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLHMAC.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLMD5.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRNG.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSA.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAKeyPair.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAPrivateKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLRSAPublicKey.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA1.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA224.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA256.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA384.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLSHA512.cpp" />\r
+     <ClCompile Include="..\..\src\lib\crypto\OSSLUtil.cpp" />\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAParameters.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAPrivateKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\RSAPublicKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\SymmetricAlgorithm.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\SymmetricKey.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\ByteString.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\RFC4880.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\salloc.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\SecureDataManager.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\SecureMemoryRegistry.cpp" />\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\Handle.cpp" />\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\HandleManager.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\Directory.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\File.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\FindOperation.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\Generation.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectFile.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectStore.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\ObjectStoreToken.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\OSAttribute.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\OSToken.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\SessionObject.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\SessionObjectStore.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\UUID.cpp" />\r
+    <ClCompile Include="..\..\src\lib\session_mgr\Session.cpp" />\r
+    <ClCompile Include="..\..\src\lib\session_mgr\SessionManager.cpp" />\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\Slot.cpp" />\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\SlotManager.cpp" />\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\Token.cpp" />\r
+    <ClCompile Include="..\..\src\lib\win32\syslog.cpp" />\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{F64541B6-FFBF-4368-B93A-A5CA8ADAD795}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>convarch</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup />\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\object_store;..\..\src\lib\slot_mgr;..\..\src\lib\session_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\crypto;..\..\src\lib\win32;..\..\src\lib\data_mgr;@DEBUGINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\object_store;..\..\src\lib\slot_mgr;..\..\src\lib\session_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\crypto;..\..\src\lib\win32;..\..\src\lib\data_mgr;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/convarch/convarch.vcxproj.user b/SoftHSMv2/win32/convarch/convarch.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.filters b/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.filters
new file mode 100644 (file)
index 0000000..9aee71d
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DHTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DSATests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ECDHTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ECDSATests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ent.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\GOSTTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\iso8859.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\randtest.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\RNGTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\RSATests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\AESTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DESTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\HashTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\test\MacTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\chisq.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\cryptotest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DHTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DSATests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ECDHTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ECDSATests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ent.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\GOSTTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\iso8859.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\randtest.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\RNGTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\RSATests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\AESTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DESTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\HashTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\MacTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.in b/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.in
new file mode 100644 (file)
index 0000000..010b890
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{07E03E0B-C525-4A72-88C6-2238896A4D8C}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>cryptotest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\crypto;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\data_mgr;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@DEBUGINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\crypto;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\data_mgr;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\AESTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DESTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DHTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\DSATests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ECDHTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ECDSATests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\ent.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\GOSTTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\HashTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\iso8859.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\MacTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\randtest.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\RNGTests.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\test\RSATests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\crypto\test\AESTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\chisq.c" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\cryptotest.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DESTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DHTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\DSATests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ECDHTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ECDSATests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\ent.c" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\GOSTTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\HashTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\iso8859.c" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\MacTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\randtest.c" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\RNGTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\test\RSATests.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.user b/SoftHSMv2/win32/cryptotest/cryptotest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.filters b/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.filters
new file mode 100644 (file)
index 0000000..645ba69
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\ByteStringTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\RFC4880Tests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\SecureDataMgrTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\ByteStringTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\datamgrtest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\RFC4880Tests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\SecureDataMgrTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.in b/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.in
new file mode 100644 (file)
index 0000000..0251af3
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{E20315B5-B49E-46D7-B7EC-1A439F347C95}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>datamgrtest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\data_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\data_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\ByteStringTests.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\RFC4880Tests.h" />\r
+    <ClInclude Include="..\..\src\lib\data_mgr\test\SecureDataMgrTests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\ByteStringTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\datamgrtest.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\RFC4880Tests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\data_mgr\test\SecureDataMgrTests.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.user b/SoftHSMv2/win32/datamgrtest/datamgrtest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/dump/dump.vcxproj.filters b/SoftHSMv2/win32/dump/dump.vcxproj.filters
new file mode 100644 (file)
index 0000000..c4546a6
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\dump\common.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\dump\tables.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\config.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\dump\softhsm2-dump-file.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/dump/dump.vcxproj.in b/SoftHSMv2/win32/dump/dump.vcxproj.in
new file mode 100644 (file)
index 0000000..2521562
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>dump</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>softhsm2-dump-file</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <TargetName>softhsm2-dump-file</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib\pkcs11;..\..\src\lib\object_store;..\..\src\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib\pkcs11;..\..\src\lib\object_store;..\..\src\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\dump\common.h" />\r
+    <ClInclude Include="..\..\src\bin\dump\tables.h" />\r
+    <ClInclude Include="..\config.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\dump\softhsm2-dump-file.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/dump/dump.vcxproj.user b/SoftHSMv2/win32/dump/dump.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.filters b/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.filters
new file mode 100644 (file)
index 0000000..38ddc83
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\test\HandleManagerTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\test\HandleManagerTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\test\handlemgrtest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.in b/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.in
new file mode 100644 (file)
index 0000000..ddc9add
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{014B1E10-EC68-4BEC-B992-F92CA2B6816F}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>handlemgrtest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\handle_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\data_mgr;..\..\src\lib\win32;@CUINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\handle_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\data_mgr;..\..\src\lib\win32;@CUINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\handle_mgr\test\HandleManagerTests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\test\HandleManagerTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\handle_mgr\test\handlemgrtest.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.user b/SoftHSMv2/win32/handlemgrtest/handlemgrtest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/keyconv/keyconv.vcxproj.filters.in b/SoftHSMv2/win32/keyconv/keyconv.vcxproj.filters.in
new file mode 100644 (file)
index 0000000..bd6ce41
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Header Files">\r
+      <UniqueIdentifier>{6f8944db-01c2-47c3-a4b4-265d91e99ba0}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Source Files">\r
+      <UniqueIdentifier>{b6a2e68c-2518-456b-8592-561c011e0390}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Source Files">\r
+      <UniqueIdentifier>{14914ba7-3ec3-4f58-a83a-4596a7f52075}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Header Files">\r
+      <UniqueIdentifier>{3253c2c0-ca7a-4902-8b31-87ab6c4c754f}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\common\getpw.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\common\library.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\keyconv\softhsm2-keyconv.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+@IF OPENSSL\r
+    <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+@END OPENSSL\r
+    <ClInclude Include="..\config.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\win32\getopt.h">\r
+      <Filter>Win32 Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv-botan.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv-ossl.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\bin\common\getpw.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\common\library.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\keyconv\base64.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\win32\getopt.cpp">\r
+      <Filter>Win32 Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\win32\getpassphase.cpp">\r
+      <Filter>Win32 Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/keyconv/keyconv.vcxproj.in b/SoftHSMv2/win32/keyconv/keyconv.vcxproj.in
new file mode 100644 (file)
index 0000000..87c1b5e
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{9B003E52-F02A-47EA-9942-2D9AE8738161}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>keyconv</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>softhsm2-keyconv</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <TargetName>softhsm2-keyconv</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\bin\common;..\..\src\bin\win32;..\..\src\lib\pkcs11;..\..\src\lib\crypto;@DEBUGINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\bin\common;..\..\src\bin\win32;..\..\src\lib\pkcs11;..\..\src\lib\crypto;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\common\getpw.h" />\r
+    <ClInclude Include="..\..\src\bin\common\library.h" />\r
+    <ClInclude Include="..\..\src\bin\keyconv\softhsm2-keyconv.h" />\r
+@IF OPENSSL\r
+    <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h" />\r
+@END OPENSSL\r
+    <ClInclude Include="..\..\src\bin\win32\getopt.h" />\r
+    <ClInclude Include="..\config.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\common\getpw.cpp" />\r
+    <ClCompile Include="..\..\src\bin\common\library.cpp" />\r
+    <ClCompile Include="..\..\src\bin\keyconv\base64.c" />\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv-botan.cpp" />\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv-ossl.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp" />\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\bin\keyconv\softhsm2-keyconv.cpp" />\r
+    <ClCompile Include="..\..\src\bin\win32\getopt.cpp" />\r
+    <ClCompile Include="..\..\src\bin\win32\getpassphase.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/keyconv/keyconv.vcxproj.user b/SoftHSMv2/win32/keyconv/keyconv.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.filters b/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.filters
new file mode 100644 (file)
index 0000000..11d8d84
--- /dev/null
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\DirectoryTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\FileTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\ObjectFileTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\ObjectStoreTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\OSTokenTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\SessionObjectStoreTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\SessionObjectTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\object_store\test\UUIDTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\DirectoryTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\FileTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\ObjectFileTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\ObjectStoreTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\OSTokenTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\objstoretest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\SessionObjectStoreTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\SessionObjectTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\UUIDTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.in b/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.in
new file mode 100644 (file)
index 0000000..d26e7cb
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{44F77533-A4A1-4175-8C4C-07106B3F9C08}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>objstoretest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\object_store;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\object_store;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\DirectoryTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\FileTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\ObjectFileTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\ObjectStoreTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\OSTokenTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\SessionObjectStoreTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\SessionObjectTests.h" />\r
+    <ClInclude Include="..\..\src\lib\object_store\test\UUIDTests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\object_store\test\DirectoryTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\FileTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\ObjectFileTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\ObjectStoreTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\objstoretest.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\OSTokenTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\SessionObjectStoreTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\SessionObjectTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\object_store\test\UUIDTests.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.user b/SoftHSMv2/win32/objstoretest/objstoretest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/p11test/p11test.vcxproj.filters b/SoftHSMv2/win32/p11test/p11test.vcxproj.filters
new file mode 100644 (file)
index 0000000..fa7e86f
--- /dev/null
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+    <Filter Include="Lib Header Files">\r
+      <UniqueIdentifier>{8440d7eb-5530-4f5e-a355-a43435742c60}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Lib Source Files">\r
+      <UniqueIdentifier>{3c33d54e-4bd1-43e0-bcc7-0d6adcfd5dc7}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Other Header Files">\r
+      <UniqueIdentifier>{ff435d2e-c67a-4f47-9731-28d88617e559}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Other Source Files">\r
+      <UniqueIdentifier>{5df8b0a3-ecc7-4876-aea2-8421c0846535}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\test\AsymEncryptDecryptTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\AsymWrapUnwrapTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\DeriveTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\DigestTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\InfoTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\InitTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\ObjectTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\RandomTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\SessionTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\SignVerifyTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\SymmetricAlgorithmTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\TestsBase.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\TestsNoPINInitBase.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\TokenTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\test\UserTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\common\osmutex.h">\r
+      <Filter>Other Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\win32\setenv.h">\r
+      <Filter>Other Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\access.h">\r
+      <Filter>Lib Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Lib Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Other Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Other Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Other Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\P11Attributes.h">\r
+      <Filter>Lib Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\P11Objects.h">\r
+      <Filter>Lib Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\SoftHSM.h">\r
+      <Filter>Lib Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\test\AsymEncryptDecryptTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\AsymWrapUnwrapTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\DeriveTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\DigestTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\InfoTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\InitTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\ObjectTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\RandomTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\SessionTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\SignVerifyTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\SymmetricAlgorithmTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\TestsBase.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\TestsNoPINInitBase.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\TokenTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\UserTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\common\osmutex.cpp">\r
+      <Filter>Other Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\win32\setenv.cpp">\r
+      <Filter>Other Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\access.cpp">\r
+      <Filter>Lib Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\main.cpp">\r
+      <Filter>Lib Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\P11Attributes.cpp">\r
+      <Filter>Lib Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\P11Objects.cpp">\r
+      <Filter>Lib Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\SoftHSM.cpp">\r
+      <Filter>Lib Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\test\p11test.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/p11test/p11test.vcxproj.in b/SoftHSMv2/win32/p11test/p11test.vcxproj.in
new file mode 100644 (file)
index 0000000..c8a493c
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{7C5EE7FC-B5FC-47BF-8164-A452FE689472}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>p11test</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\test;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\data_mgr;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>\r
+copy ..\..\src\lib\test\softhsm2.conf.win32 "$(TargetDir)\softhsm2.conf"\r
+copy ..\..\src\lib\test\softhsm2-alt.conf.win32 "$(TargetDir)\softhsm2-alt.conf"\r
+mkdir "$(TargetDir)\tokens" 2&gt; nul\r
+copy ..\..\src\lib\test\tokens\dummy.in "$(TargetDir)\tokens\dummy"\r
+      </Command>\r
+      <Message>Copying dummy test files to Debug folder</Message>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\test;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\data_mgr;..\..\src\lib\session_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>\r
+copy ..\..\src\lib\test\softhsm2.conf.win32 "$(TargetDir)\softhsm2.conf"\r
+copy ..\..\src\lib\test\softhsm2-alt.conf.win32 "$(TargetDir)\softhsm2-alt.conf"\r
+mkdir "$(TargetDir)\tokens" 2&gt; nul\r
+copy ..\..\src\lib\test\tokens\dummy.in "$(TargetDir)\tokens\dummy"\r
+      </Command>\r
+      <Message>Copying dummy test files to Release folder</Message>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\access.h" />\r
+    <ClInclude Include="..\..\src\lib\common\osmutex.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\P11Attributes.h" />\r
+    <ClInclude Include="..\..\src\lib\P11Objects.h" />\r
+    <ClInclude Include="..\..\src\lib\SoftHSM.h" />\r
+    <ClInclude Include="..\..\src\lib\test\AsymEncryptDecryptTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\AsymWrapUnwrapTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\DeriveTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\DigestTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\InfoTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\InitTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\ObjectTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\RandomTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\SessionTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\SignVerifyTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\SymmetricAlgorithmTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\TestsBase.h" />\r
+    <ClInclude Include="..\..\src\lib\test\TestsNoPINInitBase.h" />\r
+    <ClInclude Include="..\..\src\lib\test\TokenTests.h" />\r
+    <ClInclude Include="..\..\src\lib\test\UserTests.h" />\r
+    <ClInclude Include="..\..\src\lib\win32\setenv.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\access.cpp" />\r
+    <ClCompile Include="..\..\src\lib\common\osmutex.cpp" />\r
+    <ClCompile Include="..\..\src\lib\main.cpp" />\r
+    <ClCompile Include="..\..\src\lib\P11Attributes.cpp" />\r
+    <ClCompile Include="..\..\src\lib\P11Objects.cpp" />\r
+    <ClCompile Include="..\..\src\lib\SoftHSM.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\AsymEncryptDecryptTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\AsymWrapUnwrapTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\DeriveTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\DigestTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\InfoTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\InitTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\ObjectTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\p11test.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\RandomTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\SessionTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\SignVerifyTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\SymmetricAlgorithmTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\TestsBase.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\TestsNoPINInitBase.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\TokenTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\test\UserTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\win32\setenv.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/p11test/p11test.vcxproj.user b/SoftHSMv2/win32/p11test/p11test.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.filters b/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.filters
new file mode 100644 (file)
index 0000000..dbfb705
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\session_mgr\test\SessionManagerTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\session_mgr\test\SessionManagerTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\session_mgr\test\sessionmgrtest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.in b/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.in
new file mode 100644 (file)
index 0000000..572c9c3
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>sessionmgrtest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\session_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\object_store;..\..\src\lib\win32;@CUINCPATH@;@DEBUGINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\session_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\slot_mgr;..\..\src\lib\object_store;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\session_mgr\test\SessionManagerTests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\session_mgr\test\SessionManagerTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\session_mgr\test\sessionmgrtest.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.user b/SoftHSMv2/win32/sessionmgrtest/sessionmgrtest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.filters b/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.filters
new file mode 100644 (file)
index 0000000..7ddbae5
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\test\SlotManagerTests.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\test\SlotManagerTests.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\test\slotmgrtest.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.in b/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.in
new file mode 100644 (file)
index 0000000..ea52e3b
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>slotmgrtest</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\slot_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\data_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunitd.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\slot_mgr;..\..\src\lib\common;..\..\src\lib\pkcs11;..\..\src\lib\crypto;..\..\src\lib\object_store;..\..\src\lib\session_mgr;..\..\src\lib\data_mgr;..\..\src\lib\win32;@CUINCPATH@;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@CULIBPATH@;@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;cppunit.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\slot_mgr\test\SlotManagerTests.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\test\SlotManagerTests.cpp" />\r
+    <ClCompile Include="..\..\src\lib\slot_mgr\test\slotmgrtest.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.user b/SoftHSMv2/win32/slotmgrtest/slotmgrtest.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/softhsm2.sln.in b/SoftHSMv2/win32/softhsm2.sln.in
new file mode 100644 (file)
index 0000000..4d98c0d
--- /dev/null
@@ -0,0 +1,117 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 11.00\r
+# Visual C++ Express 2010\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "softhsm2", "softhsm2\softhsm2.vcxproj", "{801F5AB2-7A62-4085-B129-D15E2D717219}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "convarch", "convarch\convarch.vcxproj", "{F64541B6-FFBF-4368-B93A-A5CA8ADAD795}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyconv", "keyconv\keyconv.vcxproj", "{9B003E52-F02A-47EA-9942-2D9AE8738161}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util", "util\util.vcxproj", "{05901466-4184-47C8-9D6C-3BB99BBF5378}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219} = {801F5AB2-7A62-4085-B129-D15E2D717219}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dump", "dump\dump.vcxproj", "{F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}"\r
+EndProject\r
+@IF TESTS\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "p11test", "p11test\p11test.vcxproj", "{7C5EE7FC-B5FC-47BF-8164-A452FE689472}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219} = {801F5AB2-7A62-4085-B129-D15E2D717219}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cryptotest", "cryptotest\cryptotest.vcxproj", "{07E03E0B-C525-4A72-88C6-2238896A4D8C}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "datamgrtest", "datamgrtest\datamgrtest.vcxproj", "{E20315B5-B49E-46D7-B7EC-1A439F347C95}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "handlemgrtest", "handlemgrtest\handlemgrtest.vcxproj", "{014B1E10-EC68-4BEC-B992-F92CA2B6816F}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objstoretest", "objstoretest\objstoretest.vcxproj", "{44F77533-A4A1-4175-8C4C-07106B3F9C08}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sessionmgrtest", "sessionmgrtest\sessionmgrtest.vcxproj", "{45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slotmgrtest", "slotmgrtest\slotmgrtest.vcxproj", "{F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795} = {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}\r
+       EndProjectSection\r
+EndProject\r
+@END TESTS\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|@PLATFORM@ = Debug|@PLATFORM@\r
+               Release|@PLATFORM@ = Release|@PLATFORM@\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {801F5AB2-7A62-4085-B129-D15E2D717219}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {F64541B6-FFBF-4368-B93A-A5CA8ADAD795}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {9B003E52-F02A-47EA-9942-2D9AE8738161}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {9B003E52-F02A-47EA-9942-2D9AE8738161}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {9B003E52-F02A-47EA-9942-2D9AE8738161}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {9B003E52-F02A-47EA-9942-2D9AE8738161}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {05901466-4184-47C8-9D6C-3BB99BBF5378}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {05901466-4184-47C8-9D6C-3BB99BBF5378}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {05901466-4184-47C8-9D6C-3BB99BBF5378}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {05901466-4184-47C8-9D6C-3BB99BBF5378}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {F60ACB12-7D05-4A89-B2D1-DD16E1F3566B}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+@IF TESTS\r
+               {7C5EE7FC-B5FC-47BF-8164-A452FE689472}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {7C5EE7FC-B5FC-47BF-8164-A452FE689472}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {7C5EE7FC-B5FC-47BF-8164-A452FE689472}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {7C5EE7FC-B5FC-47BF-8164-A452FE689472}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {07E03E0B-C525-4A72-88C6-2238896A4D8C}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {07E03E0B-C525-4A72-88C6-2238896A4D8C}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {07E03E0B-C525-4A72-88C6-2238896A4D8C}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {07E03E0B-C525-4A72-88C6-2238896A4D8C}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {E20315B5-B49E-46D7-B7EC-1A439F347C95}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {E20315B5-B49E-46D7-B7EC-1A439F347C95}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {E20315B5-B49E-46D7-B7EC-1A439F347C95}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {E20315B5-B49E-46D7-B7EC-1A439F347C95}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {014B1E10-EC68-4BEC-B992-F92CA2B6816F}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {014B1E10-EC68-4BEC-B992-F92CA2B6816F}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {014B1E10-EC68-4BEC-B992-F92CA2B6816F}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {014B1E10-EC68-4BEC-B992-F92CA2B6816F}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {44F77533-A4A1-4175-8C4C-07106B3F9C08}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {44F77533-A4A1-4175-8C4C-07106B3F9C08}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {44F77533-A4A1-4175-8C4C-07106B3F9C08}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {44F77533-A4A1-4175-8C4C-07106B3F9C08}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {45E2ABF6-91A7-4AA5-A82B-0C8E54BCCCB9}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+               {F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}.Debug|@PLATFORM@.ActiveCfg = Debug|@PLATFORM@\r
+               {F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}.Debug|@PLATFORM@.Build.0 = Debug|@PLATFORM@\r
+               {F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}.Release|@PLATFORM@.ActiveCfg = Release|@PLATFORM@\r
+               {F62E31E5-0F8D-4B70-8F26-44AFA1A9E645}.Release|@PLATFORM@.Build.0 = Release|@PLATFORM@\r
+@END TESTS\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.filters b/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.filters
new file mode 100644 (file)
index 0000000..1f7b8b2
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\access.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\P11Attributes.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\P11Objects.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\SoftHSM.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\access.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\main.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\P11Attributes.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\P11Objects.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\SoftHSM.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\win32\dllmain.cc">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.in b/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.in
new file mode 100644 (file)
index 0000000..efa808e
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{801F5AB2-7A62-4085-B129-D15E2D717219}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>softhsm2</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;SOFTHSM2_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\object_store;..\..\src\lib\slot_mgr;..\..\src\lib\session_mgr;..\..\src\lib\data_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\crypto;..\..\src\lib\win32;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;SOFTHSM2_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\lib;..\..\src\lib\pkcs11;..\..\src\lib\common;..\..\src\lib\object_store;..\..\src\lib\slot_mgr;..\..\src\lib\session_mgr;..\..\src\lib\data_mgr;..\..\src\lib\handle_mgr;..\..\src\lib\crypto;..\..\src\lib\win32;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\lib\access.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+    <ClInclude Include="..\..\src\lib\P11Attributes.h" />\r
+    <ClInclude Include="..\..\src\lib\P11Objects.h" />\r
+    <ClInclude Include="..\..\src\lib\SoftHSM.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\lib\access.cpp" />\r
+    <ClCompile Include="..\..\src\lib\main.cpp" />\r
+    <ClCompile Include="..\..\src\lib\P11Attributes.cpp" />\r
+    <ClCompile Include="..\..\src\lib\P11Objects.cpp" />\r
+    <ClCompile Include="..\..\src\lib\SoftHSM.cpp" />\r
+    <ClCompile Include="..\..\src\lib\win32\dllmain.cc" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.user b/SoftHSMv2/win32/softhsm2/softhsm2.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/SoftHSMv2/win32/util/util.vcxproj.filters.in b/SoftHSMv2/win32/util/util.vcxproj.filters.in
new file mode 100644 (file)
index 0000000..2c4171b
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Header Files">\r
+      <UniqueIdentifier>{21eda3a1-8da0-4a99-967c-f218e4eecd08}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Common Source Files">\r
+      <UniqueIdentifier>{fd946626-7e24-4f78-834b-a4c0ac6dc2f5}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Header Files">\r
+      <UniqueIdentifier>{f3a7acce-323d-4465-95bf-a326189dcdd5}</UniqueIdentifier>\r
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+    </Filter>\r
+    <Filter Include="Win32 Source Files">\r
+      <UniqueIdentifier>{2b77905a-99da-49cf-9cac-aa72e7e3182b}</UniqueIdentifier>\r
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\common\findslot.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\common\getpw.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\common\library.h">\r
+      <Filter>Common Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+@IF BOTAN\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util-botan.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util-ossl.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+@END OPENSSL\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\bin\win32\getopt.h">\r
+      <Filter>Win32 Header Files</Filter>\r
+    </ClInclude>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\common\findslot.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\common\getpw.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\common\library.cpp">\r
+      <Filter>Common Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util-botan.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util-ossl.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\bin\win32\getopt.cpp">\r
+      <Filter>Win32 Source Files</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\bin\win32\getpassphase.cpp">\r
+      <Filter>Win32 Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/util/util.vcxproj.in b/SoftHSMv2/win32/util/util.vcxproj.in
new file mode 100644 (file)
index 0000000..28bdcd0
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|@PLATFORM@">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|@PLATFORM@">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>@PLATFORM@</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{05901466-4184-47C8-9D6C-3BB99BBF5378}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>util</RootNamespace>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+       <PlatformToolset>@PLATFORMTOOLSET@</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>softhsm2-util</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <TargetName>softhsm2-util</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\bin\common;..\..\src\bin\win32;..\..\src\lib\pkcs11;..\..\src\lib;..\..\src\lib\common;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\object_store;..\..\src\lib\win32\;@DEBUGINCPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@DEBUGLIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if exist @DEBUGDLLPATH@ copy @DEBUGDLLPATH@ ..\@PLATFORMDIR@$(Configuration)</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>..;..\..\src\bin\common;..\..\src\bin\win32;..\..\src\lib\pkcs11;..\..\src\lib;..\..\src\lib\common;..\..\src\lib\crypto;..\..\src\lib\data_mgr;..\..\src\lib\object_store;..\..\src\lib\win32\;@INCLUDEPATH@;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <RuntimeLibrary>@RUNTIMELIBRARY@</RuntimeLibrary>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <AdditionalLibraryDirectories>..\@PLATFORMDIR@$(Configuration);@LIBPATH@;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalDependencies>convarch.lib;@LIBNAME@;@EXTRALIBS@%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if exist @DLLPATH@ copy @DLLPATH@ ..\@PLATFORMDIR@$(Configuration)</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\src\bin\common\findslot.h" />\r
+    <ClInclude Include="..\..\src\bin\common\getpw.h" />\r
+    <ClInclude Include="..\..\src\bin\common\library.h" />\r
+@IF BOTAN\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util-botan.h" />\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util-ossl.h" />\r
+    <ClInclude Include="..\..\src\lib\crypto\OSSLComp.h" />\r
+@END OPENSSL\r
+    <ClInclude Include="..\..\src\bin\util\softhsm2-util.h" />\r
+    <ClInclude Include="..\..\src\bin\win32\getopt.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\cryptoki.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11f.h" />\r
+    <ClInclude Include="..\..\src\lib\pkcs11\pkcs11t.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\src\bin\common\findslot.cpp" />\r
+    <ClCompile Include="..\..\src\bin\common\getpw.cpp" />\r
+    <ClCompile Include="..\..\src\bin\common\library.cpp" />\r
+@IF BOTAN\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util-botan.cpp" />\r
+@END BOTAN\r
+@IF OPENSSL\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util-ossl.cpp" />\r
+    <ClCompile Include="..\..\src\lib\crypto\OSSLComp.cpp" />\r
+@END OPENSSL\r
+    <ClCompile Include="..\..\src\bin\util\softhsm2-util.cpp" />\r
+    <ClCompile Include="..\..\src\bin\win32\getopt.cpp" />\r
+    <ClCompile Include="..\..\src\bin\win32\getpassphase.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>\r
diff --git a/SoftHSMv2/win32/util/util.vcxproj.user b/SoftHSMv2/win32/util/util.vcxproj.user
new file mode 100644 (file)
index 0000000..695b5c7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+</Project>
\ No newline at end of file
diff --git a/TPM2-Plugin/README b/TPM2-Plugin/README
new file mode 100644 (file)
index 0000000..e6ed31a
--- /dev/null
@@ -0,0 +1,5 @@
+## Introduction
+
+This is TPM2-Plugin to gererate asymetric key pairs from TPM2.0 module 
+and save them in SoftHSM Token object folder in encryped fasion.
+The private part of keys can only be used for signing when it is loaded in TPM module.