From 0c89b3ccba7c9b7332ab67ae1936aff51ca62367 Mon Sep 17 00:00:00 2001 From: NingSun Date: Thu, 8 Feb 2018 08:34:03 -0800 Subject: Initial sshsm project structure Issue-ID: AAF-94 Change-Id: I5e82fff418e7567b161acf9b98013a9b85ffc5b4 Signed-off-by: NingSun --- SoftHSMv2/src/lib/Makefile.am | 52 + SoftHSMv2/src/lib/P11Attributes.cpp | 2514 +++++ SoftHSMv2/src/lib/P11Attributes.h | 1264 +++ SoftHSMv2/src/lib/P11Objects.cpp | 1807 +++ SoftHSMv2/src/lib/P11Objects.h | 398 + SoftHSMv2/src/lib/SoftHSM.cpp | 11178 +++++++++++++++++++ SoftHSMv2/src/lib/SoftHSM.h | 436 + SoftHSMv2/src/lib/access.cpp | 101 + SoftHSMv2/src/lib/access.h | 42 + SoftHSMv2/src/lib/common/Configuration.cpp | 176 + SoftHSMv2/src/lib/common/Configuration.h | 117 + SoftHSMv2/src/lib/common/HandleFactory.h | 121 + SoftHSMv2/src/lib/common/Makefile.am | 28 + SoftHSMv2/src/lib/common/MutexFactory.cpp | 192 + SoftHSMv2/src/lib/common/MutexFactory.h | 133 + SoftHSMv2/src/lib/common/Serialisable.h | 52 + SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp | 352 + SoftHSMv2/src/lib/common/SimpleConfigLoader.h | 63 + SoftHSMv2/src/lib/common/fatal.cpp | 64 + SoftHSMv2/src/lib/common/fatal.h | 52 + SoftHSMv2/src/lib/common/log.cpp | 109 + SoftHSMv2/src/lib/common/log.h | 85 + SoftHSMv2/src/lib/common/osmutex.cpp | 242 + SoftHSMv2/src/lib/common/osmutex.h | 47 + SoftHSMv2/src/lib/common/softhsm2.conf.5.in | 86 + SoftHSMv2/src/lib/common/softhsm2.conf.in | 10 + SoftHSMv2/src/lib/crypto/AESKey.cpp | 67 + SoftHSMv2/src/lib/crypto/AESKey.h | 51 + SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp | 221 + SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h | 184 + SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp | 41 + SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h | 66 + SoftHSMv2/src/lib/crypto/AsymmetricParameters.h | 59 + SoftHSMv2/src/lib/crypto/BotanAES.cpp | 354 + SoftHSMv2/src/lib/crypto/BotanAES.h | 60 + SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp | 308 + SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h | 105 + SoftHSMv2/src/lib/crypto/BotanDES.cpp | 153 + SoftHSMv2/src/lib/crypto/BotanDES.h | 63 + SoftHSMv2/src/lib/crypto/BotanDH.cpp | 408 + SoftHSMv2/src/lib/crypto/BotanDH.h | 80 + SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp | 310 + SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h | 117 + SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp | 146 + SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h | 77 + SoftHSMv2/src/lib/crypto/BotanDSA.cpp | 760 ++ SoftHSMv2/src/lib/crypto/BotanDSA.h | 86 + SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp | 243 + SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h | 86 + SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp | 162 + SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h | 78 + SoftHSMv2/src/lib/crypto/BotanECDH.cpp | 356 + SoftHSMv2/src/lib/crypto/BotanECDH.h | 79 + SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp | 71 + SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp | 259 + SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h | 87 + SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp | 151 + SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h | 79 + SoftHSMv2/src/lib/crypto/BotanECDSA.cpp | 465 + SoftHSMv2/src/lib/crypto/BotanECDSA.h | 84 + SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp | 71 + SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp | 255 + SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h | 87 + SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp | 151 + SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h | 79 + SoftHSMv2/src/lib/crypto/BotanGOST.cpp | 535 + SoftHSMv2/src/lib/crypto/BotanGOST.h | 82 + SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp | 71 + SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp | 201 + SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h | 94 + SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp | 201 + SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h | 86 + SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp | 47 + SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h | 48 + SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp | 133 + SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h | 64 + SoftHSMv2/src/lib/crypto/BotanMAC.cpp | 154 + SoftHSMv2/src/lib/crypto/BotanMAC.h | 107 + SoftHSMv2/src/lib/crypto/BotanMD5.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanMD5.h | 48 + SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp | 310 + SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h | 74 + SoftHSMv2/src/lib/crypto/BotanRNG.cpp | 87 + SoftHSMv2/src/lib/crypto/BotanRNG.h | 66 + SoftHSMv2/src/lib/crypto/BotanRSA.cpp | 1219 ++ SoftHSMv2/src/lib/crypto/BotanRSA.h | 90 + SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp | 304 + SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h | 89 + SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp | 131 + SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h | 75 + SoftHSMv2/src/lib/crypto/BotanSHA1.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanSHA1.h | 48 + SoftHSMv2/src/lib/crypto/BotanSHA224.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanSHA224.h | 48 + SoftHSMv2/src/lib/crypto/BotanSHA256.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanSHA256.h | 48 + SoftHSMv2/src/lib/crypto/BotanSHA384.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanSHA384.h | 48 + SoftHSMv2/src/lib/crypto/BotanSHA512.cpp | 45 + SoftHSMv2/src/lib/crypto/BotanSHA512.h | 48 + .../src/lib/crypto/BotanSymmetricAlgorithm.cpp | 593 + SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h | 83 + SoftHSMv2/src/lib/crypto/BotanUtil.cpp | 146 + SoftHSMv2/src/lib/crypto/BotanUtil.h | 68 + SoftHSMv2/src/lib/crypto/Botan_ecb.cpp | 153 + SoftHSMv2/src/lib/crypto/Botan_ecb.h | 107 + SoftHSMv2/src/lib/crypto/Botan_rounding.h | 68 + SoftHSMv2/src/lib/crypto/CryptoFactory.cpp | 102 + SoftHSMv2/src/lib/crypto/CryptoFactory.h | 97 + SoftHSMv2/src/lib/crypto/DESKey.cpp | 115 + SoftHSMv2/src/lib/crypto/DESKey.h | 55 + SoftHSMv2/src/lib/crypto/DHParameters.cpp | 111 + SoftHSMv2/src/lib/crypto/DHParameters.h | 81 + SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp | 120 + SoftHSMv2/src/lib/crypto/DHPrivateKey.h | 81 + SoftHSMv2/src/lib/crypto/DHPublicKey.cpp | 118 + SoftHSMv2/src/lib/crypto/DHPublicKey.h | 74 + SoftHSMv2/src/lib/crypto/DSAParameters.cpp | 108 + SoftHSMv2/src/lib/crypto/DSAParameters.h | 78 + SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp | 134 + SoftHSMv2/src/lib/crypto/DSAPrivateKey.h | 83 + SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp | 132 + SoftHSMv2/src/lib/crypto/DSAPublicKey.h | 76 + SoftHSMv2/src/lib/crypto/ECParameters.cpp | 78 + SoftHSMv2/src/lib/crypto/ECParameters.h | 64 + SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp | 106 + SoftHSMv2/src/lib/crypto/ECPrivateKey.h | 82 + SoftHSMv2/src/lib/crypto/ECPublicKey.cpp | 104 + SoftHSMv2/src/lib/crypto/ECPublicKey.h | 75 + SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp | 75 + SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h | 79 + SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp | 75 + SoftHSMv2/src/lib/crypto/GOSTPublicKey.h | 72 + SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp | 76 + SoftHSMv2/src/lib/crypto/HashAlgorithm.h | 80 + SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp | 128 + SoftHSMv2/src/lib/crypto/MacAlgorithm.h | 101 + SoftHSMv2/src/lib/crypto/Makefile.am | 126 + SoftHSMv2/src/lib/crypto/OSSLAES.cpp | 275 + SoftHSMv2/src/lib/crypto/OSSLAES.h | 64 + SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp | 84 + SoftHSMv2/src/lib/crypto/OSSLCMAC.h | 55 + SoftHSMv2/src/lib/crypto/OSSLComp.cpp | 415 + SoftHSMv2/src/lib/crypto/OSSLComp.h | 98 + SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp | 388 + SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h | 116 + SoftHSMv2/src/lib/crypto/OSSLDES.cpp | 165 + SoftHSMv2/src/lib/crypto/OSSLDES.h | 64 + SoftHSMv2/src/lib/crypto/OSSLDH.cpp | 430 + SoftHSMv2/src/lib/crypto/OSSLDH.h | 80 + SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp | 239 + SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h | 85 + SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp | 175 + SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h | 77 + SoftHSMv2/src/lib/crypto/OSSLDSA.cpp | 695 ++ SoftHSMv2/src/lib/crypto/OSSLDSA.h | 86 + SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp | 256 + SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h | 86 + SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp | 193 + SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h | 78 + SoftHSMv2/src/lib/crypto/OSSLECDH.cpp | 375 + SoftHSMv2/src/lib/crypto/OSSLECDH.h | 79 + SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp | 457 + SoftHSMv2/src/lib/crypto/OSSLECDSA.h | 80 + SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp | 71 + SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp | 187 + SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h | 85 + SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp | 131 + SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h | 76 + SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp | 244 + SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h | 77 + SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp | 133 + SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h | 66 + SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp | 220 + SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h | 77 + .../src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp | 575 + .../src/lib/crypto/OSSLEVPSymmetricAlgorithm.h | 81 + SoftHSMv2/src/lib/crypto/OSSLGOST.cpp | 658 ++ SoftHSMv2/src/lib/crypto/OSSLGOST.h | 85 + SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp | 71 + SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp | 184 + SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h | 88 + SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp | 162 + SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h | 80 + SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp | 48 + SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h | 48 + SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp | 109 + SoftHSMv2/src/lib/crypto/OSSLHMAC.h | 92 + SoftHSMv2/src/lib/crypto/OSSLMD5.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLMD5.h | 48 + SoftHSMv2/src/lib/crypto/OSSLRNG.cpp | 52 + SoftHSMv2/src/lib/crypto/OSSLRNG.h | 53 + SoftHSMv2/src/lib/crypto/OSSLRSA.cpp | 1554 +++ SoftHSMv2/src/lib/crypto/OSSLRSA.h | 87 + SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp | 70 + SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h | 67 + SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp | 320 + SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h | 90 + SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp | 155 + SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h | 76 + SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLSHA1.h | 48 + SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLSHA224.h | 48 + SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLSHA256.h | 48 + SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLSHA384.h | 48 + SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp | 46 + SoftHSMv2/src/lib/crypto/OSSLSHA512.h | 48 + SoftHSMv2/src/lib/crypto/OSSLUtil.cpp | 199 + SoftHSMv2/src/lib/crypto/OSSLUtil.h | 67 + SoftHSMv2/src/lib/crypto/PrivateKey.h | 72 + SoftHSMv2/src/lib/crypto/PublicKey.h | 65 + SoftHSMv2/src/lib/crypto/RNG.h | 67 + SoftHSMv2/src/lib/crypto/RSAParameters.cpp | 94 + SoftHSMv2/src/lib/crypto/RSAParameters.h | 74 + SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp | 186 + SoftHSMv2/src/lib/crypto/RSAPrivateKey.h | 91 + SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp | 105 + SoftHSMv2/src/lib/crypto/RSAPublicKey.h | 72 + SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp | 229 + SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h | 148 + SoftHSMv2/src/lib/crypto/SymmetricKey.cpp | 109 + SoftHSMv2/src/lib/crypto/SymmetricKey.h | 78 + SoftHSMv2/src/lib/crypto/odd.h | 72 + SoftHSMv2/src/lib/crypto/test/AESTests.cpp | 1182 ++ SoftHSMv2/src/lib/crypto/test/AESTests.h | 78 + SoftHSMv2/src/lib/crypto/test/DESTests.cpp | 1164 ++ SoftHSMv2/src/lib/crypto/test/DESTests.h | 65 + SoftHSMv2/src/lib/crypto/test/DHTests.cpp | 245 + SoftHSMv2/src/lib/crypto/test/DHTests.h | 65 + SoftHSMv2/src/lib/crypto/test/DSATests.cpp | 338 + SoftHSMv2/src/lib/crypto/test/DSATests.h | 65 + SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp | 268 + SoftHSMv2/src/lib/crypto/test/ECDHTests.h | 65 + SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp | 301 + SoftHSMv2/src/lib/crypto/test/ECDSATests.h | 65 + SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp | 304 + SoftHSMv2/src/lib/crypto/test/GOSTTests.h | 76 + SoftHSMv2/src/lib/crypto/test/HashTests.cpp | 269 + SoftHSMv2/src/lib/crypto/test/HashTests.h | 73 + SoftHSMv2/src/lib/crypto/test/MacTests.cpp | 687 ++ SoftHSMv2/src/lib/crypto/test/MacTests.h | 83 + SoftHSMv2/src/lib/crypto/test/Makefile.am | 39 + SoftHSMv2/src/lib/crypto/test/RNGTests.cpp | 85 + SoftHSMv2/src/lib/crypto/test/RNGTests.h | 59 + SoftHSMv2/src/lib/crypto/test/RSATests.cpp | 682 ++ SoftHSMv2/src/lib/crypto/test/RSATests.h | 67 + SoftHSMv2/src/lib/crypto/test/chisq.c | 144 + SoftHSMv2/src/lib/crypto/test/cryptotest.cpp | 91 + SoftHSMv2/src/lib/crypto/test/ent.c | 110 + SoftHSMv2/src/lib/crypto/test/ent.h | 56 + SoftHSMv2/src/lib/crypto/test/iso8859.c | 25 + SoftHSMv2/src/lib/crypto/test/iso8859.h | 23 + SoftHSMv2/src/lib/crypto/test/randtest.c | 190 + SoftHSMv2/src/lib/crypto/test/randtest.h | 13 + SoftHSMv2/src/lib/data_mgr/ByteString.cpp | 365 + SoftHSMv2/src/lib/data_mgr/ByteString.h | 131 + SoftHSMv2/src/lib/data_mgr/Makefile.am | 17 + SoftHSMv2/src/lib/data_mgr/RFC4880.cpp | 110 + SoftHSMv2/src/lib/data_mgr/RFC4880.h | 54 + SoftHSMv2/src/lib/data_mgr/SecureAllocator.h | 203 + SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp | 537 + SoftHSMv2/src/lib/data_mgr/SecureDataManager.h | 154 + .../src/lib/data_mgr/SecureMemoryRegistry.cpp | 142 + SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h | 73 + SoftHSMv2/src/lib/data_mgr/salloc.cpp | 126 + SoftHSMv2/src/lib/data_mgr/salloc.h | 56 + .../src/lib/data_mgr/test/ByteStringTests.cpp | 356 + SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h | 71 + SoftHSMv2/src/lib/data_mgr/test/Makefile.am | 27 + SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp | 116 + SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h | 56 + .../src/lib/data_mgr/test/SecureDataMgrTests.cpp | 207 + .../src/lib/data_mgr/test/SecureDataMgrTests.h | 56 + SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp | 91 + SoftHSMv2/src/lib/handle_mgr/Handle.cpp | 50 + SoftHSMv2/src/lib/handle_mgr/Handle.h | 62 + SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp | 239 + SoftHSMv2/src/lib/handle_mgr/HandleManager.h | 94 + SoftHSMv2/src/lib/handle_mgr/Makefile.am | 17 + .../src/lib/handle_mgr/test/HandleManagerTests.cpp | 178 + .../src/lib/handle_mgr/test/HandleManagerTests.h | 58 + SoftHSMv2/src/lib/handle_mgr/test/Makefile.am | 26 + .../src/lib/handle_mgr/test/handlemgrtest.cpp | 65 + SoftHSMv2/src/lib/main.cpp | 1187 ++ SoftHSMv2/src/lib/object_store/DB.cpp | 926 ++ SoftHSMv2/src/lib/object_store/DB.h | 188 + SoftHSMv2/src/lib/object_store/DBObject.cpp | 1493 +++ SoftHSMv2/src/lib/object_store/DBObject.h | 142 + SoftHSMv2/src/lib/object_store/DBToken.cpp | 874 ++ SoftHSMv2/src/lib/object_store/DBToken.h | 135 + SoftHSMv2/src/lib/object_store/Directory.cpp | 278 + SoftHSMv2/src/lib/object_store/Directory.h | 89 + SoftHSMv2/src/lib/object_store/File.cpp | 765 ++ SoftHSMv2/src/lib/object_store/File.h | 136 + SoftHSMv2/src/lib/object_store/FindOperation.cpp | 80 + SoftHSMv2/src/lib/object_store/FindOperation.h | 67 + SoftHSMv2/src/lib/object_store/Generation.cpp | 261 + SoftHSMv2/src/lib/object_store/Generation.h | 92 + SoftHSMv2/src/lib/object_store/Makefile.am | 34 + SoftHSMv2/src/lib/object_store/OSAttribute.cpp | 187 + SoftHSMv2/src/lib/object_store/OSAttribute.h | 103 + SoftHSMv2/src/lib/object_store/OSAttributes.h | 50 + SoftHSMv2/src/lib/object_store/OSObject.h | 95 + SoftHSMv2/src/lib/object_store/OSPathSep.h | 45 + SoftHSMv2/src/lib/object_store/OSToken.cpp | 722 ++ SoftHSMv2/src/lib/object_store/OSToken.h | 160 + SoftHSMv2/src/lib/object_store/ObjectFile.cpp | 870 ++ SoftHSMv2/src/lib/object_store/ObjectFile.h | 154 + SoftHSMv2/src/lib/object_store/ObjectStore.cpp | 187 + SoftHSMv2/src/lib/object_store/ObjectStore.h | 88 + .../src/lib/object_store/ObjectStoreToken.cpp | 84 + SoftHSMv2/src/lib/object_store/ObjectStoreToken.h | 106 + SoftHSMv2/src/lib/object_store/SessionObject.cpp | 334 + SoftHSMv2/src/lib/object_store/SessionObject.h | 132 + .../src/lib/object_store/SessionObjectStore.cpp | 212 + .../src/lib/object_store/SessionObjectStore.h | 100 + SoftHSMv2/src/lib/object_store/UUID.cpp | 68 + SoftHSMv2/src/lib/object_store/UUID.h | 48 + .../lib/object_store/test/DBObjectStoreTests.cpp | 159 + .../src/lib/object_store/test/DBObjectStoreTests.h | 79 + .../src/lib/object_store/test/DBObjectTests.cpp | 816 ++ .../src/lib/object_store/test/DBObjectTests.h | 93 + SoftHSMv2/src/lib/object_store/test/DBTests.cpp | 648 ++ SoftHSMv2/src/lib/object_store/test/DBTests.h | 134 + .../src/lib/object_store/test/DBTokenTests.cpp | 491 + SoftHSMv2/src/lib/object_store/test/DBTokenTests.h | 66 + .../src/lib/object_store/test/DirectoryTests.cpp | 227 + .../src/lib/object_store/test/DirectoryTests.h | 54 + SoftHSMv2/src/lib/object_store/test/FileTests.cpp | 340 + SoftHSMv2/src/lib/object_store/test/FileTests.h | 63 + SoftHSMv2/src/lib/object_store/test/Makefile.am | 39 + .../src/lib/object_store/test/OSTokenTests.cpp | 504 + SoftHSMv2/src/lib/object_store/test/OSTokenTests.h | 60 + .../src/lib/object_store/test/ObjectFileTests.cpp | 911 ++ .../src/lib/object_store/test/ObjectFileTests.h | 72 + .../src/lib/object_store/test/ObjectStoreTests.cpp | 278 + .../src/lib/object_store/test/ObjectStoreTests.h | 58 + .../object_store/test/SessionObjectStoreTests.cpp | 319 + .../object_store/test/SessionObjectStoreTests.h | 56 + .../lib/object_store/test/SessionObjectTests.cpp | 436 + .../src/lib/object_store/test/SessionObjectTests.h | 68 + SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp | 61 + SoftHSMv2/src/lib/object_store/test/UUIDTests.h | 54 + .../src/lib/object_store/test/objstoretest.cpp | 91 + SoftHSMv2/src/lib/pkcs11/cryptoki.h | 94 + SoftHSMv2/src/lib/pkcs11/pkcs11.h | 265 + SoftHSMv2/src/lib/pkcs11/pkcs11f.h | 939 ++ SoftHSMv2/src/lib/pkcs11/pkcs11t.h | 2003 ++++ SoftHSMv2/src/lib/session_mgr/Makefile.am | 17 + SoftHSMv2/src/lib/session_mgr/Session.cpp | 454 + SoftHSMv2/src/lib/session_mgr/Session.h | 175 + SoftHSMv2/src/lib/session_mgr/SessionManager.cpp | 246 + SoftHSMv2/src/lib/session_mgr/SessionManager.h | 66 + SoftHSMv2/src/lib/session_mgr/test/Makefile.am | 26 + .../lib/session_mgr/test/SessionManagerTests.cpp | 260 + .../src/lib/session_mgr/test/SessionManagerTests.h | 53 + .../src/lib/session_mgr/test/sessionmgrtest.cpp | 111 + SoftHSMv2/src/lib/slot_mgr/Makefile.am | 18 + SoftHSMv2/src/lib/slot_mgr/Slot.cpp | 116 + SoftHSMv2/src/lib/slot_mgr/Slot.h | 81 + SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp | 179 + SoftHSMv2/src/lib/slot_mgr/SlotManager.h | 71 + SoftHSMv2/src/lib/slot_mgr/Token.cpp | 573 + SoftHSMv2/src/lib/slot_mgr/Token.h | 112 + SoftHSMv2/src/lib/slot_mgr/test/Makefile.am | 25 + .../src/lib/slot_mgr/test/SlotManagerTests.cpp | 485 + SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h | 60 + SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp | 91 + SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp | 206 + SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h | 55 + SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp | 228 + SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h | 55 + SoftHSMv2/src/lib/test/DeriveTests.cpp | 737 ++ SoftHSMv2/src/lib/test/DeriveTests.h | 73 + SoftHSMv2/src/lib/test/DigestTests.cpp | 326 + SoftHSMv2/src/lib/test/DigestTests.h | 60 + SoftHSMv2/src/lib/test/InfoTests.cpp | 320 + SoftHSMv2/src/lib/test/InfoTests.h | 65 + SoftHSMv2/src/lib/test/InitTests.cpp | 247 + SoftHSMv2/src/lib/test/InitTests.h | 65 + SoftHSMv2/src/lib/test/Makefile.am | 40 + SoftHSMv2/src/lib/test/ObjectTests.cpp | 2393 ++++ SoftHSMv2/src/lib/test/ObjectTests.h | 194 + SoftHSMv2/src/lib/test/README | 17 + SoftHSMv2/src/lib/test/RandomTests.cpp | 94 + SoftHSMv2/src/lib/test/RandomTests.h | 51 + SoftHSMv2/src/lib/test/SessionTests.cpp | 176 + SoftHSMv2/src/lib/test/SessionTests.h | 57 + SoftHSMv2/src/lib/test/SignVerifyTests.cpp | 830 ++ SoftHSMv2/src/lib/test/SignVerifyTests.h | 73 + SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp | 998 ++ SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h | 80 + SoftHSMv2/src/lib/test/TestsBase.cpp | 49 + SoftHSMv2/src/lib/test/TestsBase.h | 44 + SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp | 160 + SoftHSMv2/src/lib/test/TestsNoPINInitBase.h | 78 + SoftHSMv2/src/lib/test/TokenTests.cpp | 98 + SoftHSMv2/src/lib/test/TokenTests.h | 50 + SoftHSMv2/src/lib/test/UserTests.cpp | 270 + SoftHSMv2/src/lib/test/UserTests.h | 56 + SoftHSMv2/src/lib/test/p11test.cpp | 92 + SoftHSMv2/src/lib/test/softhsm2-alt.conf.in | 6 + SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32 | 6 + SoftHSMv2/src/lib/test/softhsm2.conf.in | 6 + SoftHSMv2/src/lib/test/softhsm2.conf.win32 | 6 + SoftHSMv2/src/lib/test/tokens/dummy.in | 0 SoftHSMv2/src/lib/win32/dllmain.cc | 18 + SoftHSMv2/src/lib/win32/setenv.cpp | 20 + SoftHSMv2/src/lib/win32/setenv.h | 12 + SoftHSMv2/src/lib/win32/syslog.cpp | 69 + SoftHSMv2/src/lib/win32/syslog.h | 46 + 429 files changed, 92318 insertions(+) create mode 100644 SoftHSMv2/src/lib/Makefile.am create mode 100644 SoftHSMv2/src/lib/P11Attributes.cpp create mode 100644 SoftHSMv2/src/lib/P11Attributes.h create mode 100644 SoftHSMv2/src/lib/P11Objects.cpp create mode 100644 SoftHSMv2/src/lib/P11Objects.h create mode 100644 SoftHSMv2/src/lib/SoftHSM.cpp create mode 100644 SoftHSMv2/src/lib/SoftHSM.h create mode 100644 SoftHSMv2/src/lib/access.cpp create mode 100644 SoftHSMv2/src/lib/access.h create mode 100644 SoftHSMv2/src/lib/common/Configuration.cpp create mode 100644 SoftHSMv2/src/lib/common/Configuration.h create mode 100644 SoftHSMv2/src/lib/common/HandleFactory.h create mode 100644 SoftHSMv2/src/lib/common/Makefile.am create mode 100644 SoftHSMv2/src/lib/common/MutexFactory.cpp create mode 100644 SoftHSMv2/src/lib/common/MutexFactory.h create mode 100644 SoftHSMv2/src/lib/common/Serialisable.h create mode 100644 SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp create mode 100644 SoftHSMv2/src/lib/common/SimpleConfigLoader.h create mode 100644 SoftHSMv2/src/lib/common/fatal.cpp create mode 100644 SoftHSMv2/src/lib/common/fatal.h create mode 100644 SoftHSMv2/src/lib/common/log.cpp create mode 100644 SoftHSMv2/src/lib/common/log.h create mode 100644 SoftHSMv2/src/lib/common/osmutex.cpp create mode 100644 SoftHSMv2/src/lib/common/osmutex.h create mode 100644 SoftHSMv2/src/lib/common/softhsm2.conf.5.in create mode 100644 SoftHSMv2/src/lib/common/softhsm2.conf.in create mode 100644 SoftHSMv2/src/lib/crypto/AESKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/AESKey.h create mode 100644 SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/AsymmetricParameters.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanAES.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanAES.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDES.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDES.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDH.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDH.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSA.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDH.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDH.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSA.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOST.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOST.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanMAC.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanMAC.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanMD5.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanMD5.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanRNG.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanRNG.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSA.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA1.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA1.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA224.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA224.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA256.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA256.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA384.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA384.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA512.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSHA512.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/BotanUtil.cpp create mode 100644 SoftHSMv2/src/lib/crypto/BotanUtil.h create mode 100644 SoftHSMv2/src/lib/crypto/Botan_ecb.cpp create mode 100644 SoftHSMv2/src/lib/crypto/Botan_ecb.h create mode 100644 SoftHSMv2/src/lib/crypto/Botan_rounding.h create mode 100644 SoftHSMv2/src/lib/crypto/CryptoFactory.cpp create mode 100644 SoftHSMv2/src/lib/crypto/CryptoFactory.h create mode 100644 SoftHSMv2/src/lib/crypto/DESKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DESKey.h create mode 100644 SoftHSMv2/src/lib/crypto/DHParameters.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DHParameters.h create mode 100644 SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DHPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/DHPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DHPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/DSAParameters.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DSAParameters.h create mode 100644 SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/DSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/ECParameters.cpp create mode 100644 SoftHSMv2/src/lib/crypto/ECParameters.h create mode 100644 SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/ECPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/ECPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/ECPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/GOSTPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/HashAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/MacAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/Makefile.am create mode 100644 SoftHSMv2/src/lib/crypto/OSSLAES.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLAES.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLCMAC.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLComp.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLComp.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDES.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDES.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDH.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDH.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSA.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECDH.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECDH.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECDSA.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOST.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOST.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLHMAC.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLMD5.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLMD5.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRNG.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRNG.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSA.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSA.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA1.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA224.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA256.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA384.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLSHA512.h create mode 100644 SoftHSMv2/src/lib/crypto/OSSLUtil.cpp create mode 100644 SoftHSMv2/src/lib/crypto/OSSLUtil.h create mode 100644 SoftHSMv2/src/lib/crypto/PrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/PublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/RNG.h create mode 100644 SoftHSMv2/src/lib/crypto/RSAParameters.cpp create mode 100644 SoftHSMv2/src/lib/crypto/RSAParameters.h create mode 100644 SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/RSAPrivateKey.h create mode 100644 SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/RSAPublicKey.h create mode 100644 SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp create mode 100644 SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h create mode 100644 SoftHSMv2/src/lib/crypto/SymmetricKey.cpp create mode 100644 SoftHSMv2/src/lib/crypto/SymmetricKey.h create mode 100644 SoftHSMv2/src/lib/crypto/odd.h create mode 100644 SoftHSMv2/src/lib/crypto/test/AESTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/AESTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/DESTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/DESTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/DHTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/DHTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/DSATests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/DSATests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/ECDHTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/ECDSATests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/GOSTTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/HashTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/HashTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/MacTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/MacTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/crypto/test/RNGTests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/RNGTests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/RSATests.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/RSATests.h create mode 100644 SoftHSMv2/src/lib/crypto/test/chisq.c create mode 100644 SoftHSMv2/src/lib/crypto/test/cryptotest.cpp create mode 100644 SoftHSMv2/src/lib/crypto/test/ent.c create mode 100644 SoftHSMv2/src/lib/crypto/test/ent.h create mode 100644 SoftHSMv2/src/lib/crypto/test/iso8859.c create mode 100644 SoftHSMv2/src/lib/crypto/test/iso8859.h create mode 100644 SoftHSMv2/src/lib/crypto/test/randtest.c create mode 100644 SoftHSMv2/src/lib/crypto/test/randtest.h create mode 100644 SoftHSMv2/src/lib/data_mgr/ByteString.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/ByteString.h create mode 100644 SoftHSMv2/src/lib/data_mgr/Makefile.am create mode 100644 SoftHSMv2/src/lib/data_mgr/RFC4880.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/RFC4880.h create mode 100644 SoftHSMv2/src/lib/data_mgr/SecureAllocator.h create mode 100644 SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/SecureDataManager.h create mode 100644 SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h create mode 100644 SoftHSMv2/src/lib/data_mgr/salloc.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/salloc.h create mode 100644 SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h create mode 100644 SoftHSMv2/src/lib/data_mgr/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h create mode 100644 SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp create mode 100644 SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h create mode 100644 SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp create mode 100644 SoftHSMv2/src/lib/handle_mgr/Handle.cpp create mode 100644 SoftHSMv2/src/lib/handle_mgr/Handle.h create mode 100644 SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp create mode 100644 SoftHSMv2/src/lib/handle_mgr/HandleManager.h create mode 100644 SoftHSMv2/src/lib/handle_mgr/Makefile.am create mode 100644 SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.cpp create mode 100644 SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.h create mode 100644 SoftHSMv2/src/lib/handle_mgr/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/handle_mgr/test/handlemgrtest.cpp create mode 100644 SoftHSMv2/src/lib/main.cpp create mode 100644 SoftHSMv2/src/lib/object_store/DB.cpp create mode 100644 SoftHSMv2/src/lib/object_store/DB.h create mode 100644 SoftHSMv2/src/lib/object_store/DBObject.cpp create mode 100644 SoftHSMv2/src/lib/object_store/DBObject.h create mode 100644 SoftHSMv2/src/lib/object_store/DBToken.cpp create mode 100644 SoftHSMv2/src/lib/object_store/DBToken.h create mode 100644 SoftHSMv2/src/lib/object_store/Directory.cpp create mode 100644 SoftHSMv2/src/lib/object_store/Directory.h create mode 100644 SoftHSMv2/src/lib/object_store/File.cpp create mode 100644 SoftHSMv2/src/lib/object_store/File.h create mode 100644 SoftHSMv2/src/lib/object_store/FindOperation.cpp create mode 100644 SoftHSMv2/src/lib/object_store/FindOperation.h create mode 100644 SoftHSMv2/src/lib/object_store/Generation.cpp create mode 100644 SoftHSMv2/src/lib/object_store/Generation.h create mode 100644 SoftHSMv2/src/lib/object_store/Makefile.am create mode 100644 SoftHSMv2/src/lib/object_store/OSAttribute.cpp create mode 100644 SoftHSMv2/src/lib/object_store/OSAttribute.h create mode 100644 SoftHSMv2/src/lib/object_store/OSAttributes.h create mode 100644 SoftHSMv2/src/lib/object_store/OSObject.h create mode 100644 SoftHSMv2/src/lib/object_store/OSPathSep.h create mode 100644 SoftHSMv2/src/lib/object_store/OSToken.cpp create mode 100644 SoftHSMv2/src/lib/object_store/OSToken.h create mode 100644 SoftHSMv2/src/lib/object_store/ObjectFile.cpp create mode 100644 SoftHSMv2/src/lib/object_store/ObjectFile.h create mode 100644 SoftHSMv2/src/lib/object_store/ObjectStore.cpp create mode 100644 SoftHSMv2/src/lib/object_store/ObjectStore.h create mode 100644 SoftHSMv2/src/lib/object_store/ObjectStoreToken.cpp create mode 100644 SoftHSMv2/src/lib/object_store/ObjectStoreToken.h create mode 100644 SoftHSMv2/src/lib/object_store/SessionObject.cpp create mode 100644 SoftHSMv2/src/lib/object_store/SessionObject.h create mode 100644 SoftHSMv2/src/lib/object_store/SessionObjectStore.cpp create mode 100644 SoftHSMv2/src/lib/object_store/SessionObjectStore.h create mode 100644 SoftHSMv2/src/lib/object_store/UUID.cpp create mode 100644 SoftHSMv2/src/lib/object_store/UUID.h create mode 100644 SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/DBObjectTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/DBTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/DBTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/DBTokenTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/DirectoryTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/FileTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/FileTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/OSTokenTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp create mode 100644 SoftHSMv2/src/lib/object_store/test/UUIDTests.h create mode 100644 SoftHSMv2/src/lib/object_store/test/objstoretest.cpp create mode 100644 SoftHSMv2/src/lib/pkcs11/cryptoki.h create mode 100644 SoftHSMv2/src/lib/pkcs11/pkcs11.h create mode 100644 SoftHSMv2/src/lib/pkcs11/pkcs11f.h create mode 100644 SoftHSMv2/src/lib/pkcs11/pkcs11t.h create mode 100644 SoftHSMv2/src/lib/session_mgr/Makefile.am create mode 100644 SoftHSMv2/src/lib/session_mgr/Session.cpp create mode 100644 SoftHSMv2/src/lib/session_mgr/Session.h create mode 100644 SoftHSMv2/src/lib/session_mgr/SessionManager.cpp create mode 100644 SoftHSMv2/src/lib/session_mgr/SessionManager.h create mode 100644 SoftHSMv2/src/lib/session_mgr/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.cpp create mode 100644 SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.h create mode 100644 SoftHSMv2/src/lib/session_mgr/test/sessionmgrtest.cpp create mode 100644 SoftHSMv2/src/lib/slot_mgr/Makefile.am create mode 100644 SoftHSMv2/src/lib/slot_mgr/Slot.cpp create mode 100644 SoftHSMv2/src/lib/slot_mgr/Slot.h create mode 100644 SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp create mode 100644 SoftHSMv2/src/lib/slot_mgr/SlotManager.h create mode 100644 SoftHSMv2/src/lib/slot_mgr/Token.cpp create mode 100644 SoftHSMv2/src/lib/slot_mgr/Token.h create mode 100644 SoftHSMv2/src/lib/slot_mgr/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.cpp create mode 100644 SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h create mode 100644 SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp create mode 100644 SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp create mode 100644 SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h create mode 100644 SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp create mode 100644 SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h create mode 100644 SoftHSMv2/src/lib/test/DeriveTests.cpp create mode 100644 SoftHSMv2/src/lib/test/DeriveTests.h create mode 100644 SoftHSMv2/src/lib/test/DigestTests.cpp create mode 100644 SoftHSMv2/src/lib/test/DigestTests.h create mode 100644 SoftHSMv2/src/lib/test/InfoTests.cpp create mode 100644 SoftHSMv2/src/lib/test/InfoTests.h create mode 100644 SoftHSMv2/src/lib/test/InitTests.cpp create mode 100644 SoftHSMv2/src/lib/test/InitTests.h create mode 100644 SoftHSMv2/src/lib/test/Makefile.am create mode 100644 SoftHSMv2/src/lib/test/ObjectTests.cpp create mode 100644 SoftHSMv2/src/lib/test/ObjectTests.h create mode 100644 SoftHSMv2/src/lib/test/README create mode 100644 SoftHSMv2/src/lib/test/RandomTests.cpp create mode 100644 SoftHSMv2/src/lib/test/RandomTests.h create mode 100644 SoftHSMv2/src/lib/test/SessionTests.cpp create mode 100644 SoftHSMv2/src/lib/test/SessionTests.h create mode 100644 SoftHSMv2/src/lib/test/SignVerifyTests.cpp create mode 100644 SoftHSMv2/src/lib/test/SignVerifyTests.h create mode 100644 SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp create mode 100644 SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h create mode 100644 SoftHSMv2/src/lib/test/TestsBase.cpp create mode 100644 SoftHSMv2/src/lib/test/TestsBase.h create mode 100644 SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp create mode 100644 SoftHSMv2/src/lib/test/TestsNoPINInitBase.h create mode 100644 SoftHSMv2/src/lib/test/TokenTests.cpp create mode 100644 SoftHSMv2/src/lib/test/TokenTests.h create mode 100644 SoftHSMv2/src/lib/test/UserTests.cpp create mode 100644 SoftHSMv2/src/lib/test/UserTests.h create mode 100644 SoftHSMv2/src/lib/test/p11test.cpp create mode 100644 SoftHSMv2/src/lib/test/softhsm2-alt.conf.in create mode 100644 SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32 create mode 100644 SoftHSMv2/src/lib/test/softhsm2.conf.in create mode 100644 SoftHSMv2/src/lib/test/softhsm2.conf.win32 create mode 100644 SoftHSMv2/src/lib/test/tokens/dummy.in create mode 100644 SoftHSMv2/src/lib/win32/dllmain.cc create mode 100644 SoftHSMv2/src/lib/win32/setenv.cpp create mode 100644 SoftHSMv2/src/lib/win32/setenv.h create mode 100644 SoftHSMv2/src/lib/win32/syslog.cpp create mode 100644 SoftHSMv2/src/lib/win32/syslog.h (limited to 'SoftHSMv2/src/lib') diff --git a/SoftHSMv2/src/lib/Makefile.am b/SoftHSMv2/src/lib/Makefile.am new file mode 100644 index 0000000..f3f5bb4 --- /dev/null +++ b/SoftHSMv2/src/lib/Makefile.am @@ -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 index 0000000..28d0f9b --- /dev/null +++ b/SoftHSMv2/src/lib/P11Attributes.cpp @@ -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 +#include + +// 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& 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::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::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 set = attr.getMechanismTypeSetValue(); + for (std::set::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 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 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 (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 (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 (attr->type, elem)); + } + } + + // Store data + osobject->setAttribute(type, data); + + return CKR_OK; +} + +/***************************************** + * CKA_UNWRAP_TEMPLATE + *****************************************/ + +// Set default value +bool P11AttrUnwrapTemplate::setDefault() +{ + std::map 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 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 (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 (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 (attr->type, elem)); + } + } + + // Store data + osobject->setAttribute(type, data); + + return CKR_OK; +} + +/***************************************** + * CKA_ALLOWED_MECHANISMS + *****************************************/ + +// Set default value +bool P11AttrAllowedMechanisms::setDefault() +{ + std::set 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 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 index 0000000..3cddf30 --- /dev/null +++ b/SoftHSMv2/src/lib/P11Attributes.h @@ -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 index 0000000..c58d4ec --- /dev/null +++ b/SoftHSMv2/src/lib/P11Objects.cpp @@ -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 +#include + +// Constructor +P11Object::P11Object() +{ + initialized = false; + osobject = NULL; +} + +// Destructor +P11Object::~P11Object() +{ + std::map cleanUp = attributes; + attributes.clear(); + + for (std::map::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::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 index 0000000..942a8c4 --- /dev/null +++ b/SoftHSMv2/src/lib/P11Objects.h @@ -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 + +class P11Object +{ +public: + // Destructor + virtual ~P11Object(); + +protected: + // Constructor + P11Object(); + + // The object + OSObject* osobject; + + // The attributes + std::map 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 index 0000000..b06efc2 --- /dev/null +++ b/SoftHSMv2/src/lib/SoftHSM.cpp @@ -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 + +// Initialise the one-and-only instance + +#ifdef HAVE_CXX11 + +std::unique_ptr MutexFactory::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif +std::unique_ptr SoftHSM::instance(nullptr); + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr BotanCryptoFactory::instance(NULL); +#endif +std::auto_ptr 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 allObjects; + token->getObjects(allObjects); + sessionObjectStore->getObjects(slot->getSlotID(),allObjects); + + std::set handles; + std::set::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; iattributeExists(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 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 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 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 index 0000000..19909e4 --- /dev/null +++ b/SoftHSMv2/src/lib/SoftHSM.h @@ -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 + +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 instance; +#else + static std::auto_ptr 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 index 0000000..66473d1 --- /dev/null +++ b/SoftHSMv2/src/lib/access.cpp @@ -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 +#include + +// 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 index 0000000..36f303f --- /dev/null +++ b/SoftHSMv2/src/lib/access.h @@ -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 index 0000000..a7f6cc6 --- /dev/null +++ b/SoftHSMv2/src/lib/common/Configuration.cpp @@ -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 +#include +#include "Configuration.h" +#include "log.h" + +// Initialise the one-and-only instance +#ifdef HAVE_CXX11 +std::unique_ptr Configuration::instance(nullptr); +#else +std::auto_ptr 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 index 0000000..eacb493 --- /dev/null +++ b/SoftHSMv2/src/lib/common/Configuration.h @@ -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 +#include +#include + +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 instance; +#else + static std::auto_ptr instance; +#endif + + std::map stringConfiguration; + std::map integerConfiguration; + std::map 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 index 0000000..0b9dc1f --- /dev/null +++ b/SoftHSMv2/src/lib/common/HandleFactory.h @@ -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 +#include + +template 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 handleMap; + + // The set of recycled handles + std::queue 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 index 0000000..bf18b1a --- /dev/null +++ b/SoftHSMv2/src/lib/common/Makefile.am @@ -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 index 0000000..1cfc0da --- /dev/null +++ b/SoftHSMv2/src/lib/common/MutexFactory.cpp @@ -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 +#include + +/***************************************************************************** + 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 index 0000000..167dc3d --- /dev/null +++ b/SoftHSMv2/src/lib/common/MutexFactory.h @@ -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 + +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 instance; +#else + static std::auto_ptr 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 index 0000000..819940e --- /dev/null +++ b/SoftHSMv2/src/lib/common/Serialisable.h @@ -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 index 0000000..3212d82 --- /dev/null +++ b/SoftHSMv2/src/lib/common/SimpleConfigLoader.cpp @@ -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 +#include +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include "config.h" +#if defined(HAVE_GETPWUID_R) +# include +# include +#endif +#include "SimpleConfigLoader.h" +#include "log.h" +#include "Configuration.h" + +// Initialise the one-and-only instance +#ifdef HAVE_CXX11 +std::unique_ptr SimpleConfigLoader::instance(nullptr); +#else +std::auto_ptr 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 + // + // = + // # 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 index 0000000..e992cfb --- /dev/null +++ b/SoftHSMv2/src/lib/common/SimpleConfigLoader.h @@ -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 +#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 instance; +#else + static std::auto_ptr 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 index 0000000..4da26f4 --- /dev/null +++ b/SoftHSMv2/src/lib/common/fatal.cpp @@ -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 index 0000000..124265e --- /dev/null +++ b/SoftHSMv2/src/lib/common/fatal.h @@ -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 index 0000000..7400f6a --- /dev/null +++ b/SoftHSMv2/src/lib/common/log.cpp @@ -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 +#include +#include +#include +#include +#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 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 index 0000000..cf91aaf --- /dev/null +++ b/SoftHSMv2/src/lib/common/log.h @@ -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 +#include + +/* 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 index 0000000..28db10e --- /dev/null +++ b/SoftHSMv2/src/lib/common/osmutex.cpp @@ -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 +#include + +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 index 0000000..103dc67 --- /dev/null +++ b/SoftHSMv2/src/lib/common/osmutex.h @@ -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 index 0000000..5291a09 --- /dev/null +++ b/SoftHSMv2/src/lib/common/softhsm2.conf.5.in @@ -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 + = +.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 index 0000000..3d5728d --- /dev/null +++ b/SoftHSMv2/src/lib/common/softhsm2.conf.in @@ -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 index 0000000..9b511b5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AESKey.cpp @@ -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 index 0000000..6505b9d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AESKey.h @@ -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 index 0000000..20a50a5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.cpp @@ -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 index 0000000..ca0d840 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AsymmetricAlgorithm.h @@ -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 index 0000000..a31c17e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.cpp @@ -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 index 0000000..8ff63ef --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AsymmetricKeyPair.h @@ -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 index 0000000..12c607b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/AsymmetricParameters.h @@ -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 index 0000000..0c67a09 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanAES.cpp @@ -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 +#include +#include + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include +#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 data(in.size()); + memcpy(data.data(), in.const_byte_str(), in.size()); + Botan::secure_vector wrapped; +#else + Botan::MemoryVector data(in.size()); + memcpy(data.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector 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 data(in.size()); + memcpy(data.data(), in.const_byte_str(), in.size()); + Botan::secure_vector wrapped; +#else + Botan::MemoryVector data(in.size()); + memcpy(data.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector 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 wrapped(in.size()); + memcpy(wrapped.data(), in.const_byte_str(), in.size()); + Botan::secure_vector unwrapped; +#else + Botan::MemoryVector wrapped(in.size()); + memcpy(wrapped.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector 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 wrapped(in.size()); + memcpy(wrapped.data(), in.const_byte_str(), in.size()); + Botan::secure_vector unwrapped; +#else + Botan::MemoryVector wrapped(in.size()); + memcpy(wrapped.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector 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 index 0000000..4bc38ab --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanAES.h @@ -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 +#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 index 0000000..b4df224 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.cpp @@ -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 + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include +#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::iterator it; + for (it=rngs.begin(); it != rngs.end(); it++) + { + delete (BotanRNG*)it->second; + } +#elif _WIN32 + std::map::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::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::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 index 0000000..df7556d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanCryptoFactory.h @@ -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 +#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 +#include +#include + +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 instance; +#else + static std::auto_ptr instance; +#endif + + // Thread specific RNG +#ifdef HAVE_PTHREAD_H + std::map rngs; +#elif _WIN32 + std::map 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 index 0000000..393cf4d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDES.cpp @@ -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 +#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 index 0000000..4f81fe6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDES.h @@ -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 +#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 index 0000000..5adc239 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDH.cpp @@ -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 +#include +#include +#include +#include + +// 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 index 0000000..af2ac59 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDH.h @@ -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 + +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 index 0000000..10c2131 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.cpp @@ -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 index 0000000..629c6fd --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHKeyPair.h @@ -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 index 0000000..cb7a530 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.cpp @@ -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 +#include +#include +#include +#include +#include + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) +std::vector BotanDH_PrivateKey::public_value() const +{ + return impl->public_value(); +} +#else +Botan::MemoryVector 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& 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& 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 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 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 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 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 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 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 keydata; +#else + Botan::SecureVector keydata; +#endif + Botan::AlgorithmIdentifier alg_id; + BotanDH_PrivateKey* key = NULL; + try + { + Botan::BER_Decoder(source) + .start_cons(Botan::SEQUENCE) + .decode_and_check(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 index 0000000..5991c21 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHPrivateKey.h @@ -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 +#include + +// 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 public_value() const; +#else + Botan::MemoryVector 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& key_bits, + Botan::RandomNumberGenerator& rng); +#else + BotanDH_PrivateKey(const Botan::AlgorithmIdentifier& alg_id, + const Botan::MemoryRegion& 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 index 0000000..16c4b12 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.cpp @@ -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 + +// 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 index 0000000..66e90c2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDHPublicKey.h @@ -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 + +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 index 0000000..ab3aa01 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSA.cpp @@ -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 +#include +#include +#include +#include + +// 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 signResult; +#else + Botan::SecureVector 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 signResult; +#else + Botan::SecureVector 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 index 0000000..dd10016 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSA.h @@ -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 + +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 index 0000000..9d98125 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.cpp @@ -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 index 0000000..beb07e1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAKeyPair.h @@ -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 index 0000000..a7f1c9b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.cpp @@ -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 +#include +#include +#include +#include +#include + +// 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 ber = Botan::PKCS8::BER_encode(*dsa); +#else + const Botan::SecureVector 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 keydata; +#else + Botan::SecureVector keydata; +#endif + Botan::AlgorithmIdentifier alg_id; + Botan::DSA_PrivateKey* key = NULL; + try + { + + Botan::BER_Decoder(source) + .start_cons(Botan::SEQUENCE) + .decode_and_check(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 index 0000000..5594967 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAPrivateKey.h @@ -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 + +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 index 0000000..a1593d6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.cpp @@ -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 + +// 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 index 0000000..e4d683d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanDSAPublicKey.h @@ -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 + +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 index 0000000..2741734 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDH.cpp @@ -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 +#include +#include +#include +#include + +// 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 index 0000000..3fac507 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDH.h @@ -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 + +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 index 0000000..74313d9 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.cpp @@ -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 index 0000000..a9786b9 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHKeyPair.h @@ -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 index 0000000..043e6e1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +// 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(oid, parameters); + const Botan::secure_vector 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(oid, parameters); + const Botan::secure_vector 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(oid, parameters); + const Botan::SecureVector 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 keydata; +#else + Botan::SecureVector 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(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 index 0000000..d84e046 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHPrivateKey.h @@ -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 + +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 index 0000000..6201f18 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.cpp @@ -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 + +// 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 index 0000000..0a10743 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDHPublicKey.h @@ -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 + +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 index 0000000..06b7a0f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSA.cpp @@ -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 +#include +#include +#include +#include + +// 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 signResult; +#else + Botan::SecureVector 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 index 0000000..826d318 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSA.h @@ -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 + +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 index 0000000..ccc04d7 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.cpp @@ -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 index 0000000..960923d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAKeyPair.h @@ -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 index 0000000..a276cb0 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +// 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); + const Botan::secure_vector 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); + const Botan::secure_vector 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 parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); + const Botan::SecureVector 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 keydata; +#else + Botan::SecureVector keydata; +#endif + Botan::AlgorithmIdentifier alg_id; + Botan::ECDSA_PrivateKey* key = NULL; + try + { + Botan::BER_Decoder(source) + .start_cons(Botan::SEQUENCE) + .decode_and_check(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 index 0000000..4477442 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAPrivateKey.h @@ -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 + +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 index 0000000..3409d88 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.cpp @@ -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 + +// 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 index 0000000..6ad0720 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanECDSAPublicKey.h @@ -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 + +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 index 0000000..ab02d54 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOST.cpp @@ -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 +#include +#include +#include +#include + +// 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 signResult; +#else + Botan::SecureVector 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 index 0000000..a8085ab --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOST.h @@ -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 + +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 index 0000000..08c3de5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.cpp @@ -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 index 0000000..2ff1b95 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTKeyPair.h @@ -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 index 0000000..890f135 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.cpp @@ -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 + +// 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 index 0000000..cdc825b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTPrivateKey.h @@ -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 + +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 index 0000000..cebce66 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.cpp @@ -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 + +// 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 index 0000000..6d7e8fc --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTPublicKey.h @@ -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 + +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 index 0000000..344cdcd --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.cpp @@ -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 + +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 index 0000000..b0ee374 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanGOSTR3411.h @@ -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 + +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 index 0000000..9630dfc --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.cpp @@ -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 + +// 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 index 0000000..dde82db --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanHashAlgorithm.h @@ -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 + +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 index 0000000..b45f127 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMAC.cpp @@ -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 index 0000000..4db9aee --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMAC.h @@ -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 +#include + +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 index 0000000..382f53d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMD5.cpp @@ -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 + +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 index 0000000..6542019 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMD5.h @@ -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 + +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 index 0000000..6c863f7 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.cpp @@ -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 +#include +#include +#include +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,26) +#include +#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 signResult; +#else + Botan::SecureVector 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 macResult; +#else + Botan::SecureVector 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 index 0000000..ac71009 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanMacAlgorithm.h @@ -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 +#include "config.h" +#include "SymmetricKey.h" +#include "MacAlgorithm.h" +#include + +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 index 0000000..fa6509d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRNG.cpp @@ -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 + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include +#else +#include +#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 index 0000000..f14b22e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRNG.h @@ -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 index 0000000..2fbb4e2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSA.cpp @@ -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 +#include +#include +#include + +// 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 signResult; +#else + Botan::SecureVector 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 signResult; +#else + Botan::SecureVector 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 encResult; +#else + Botan::SecureVector 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 decResult; +#else + Botan::SecureVector 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 index 0000000..f9b6554 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSA.h @@ -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 + +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 index 0000000..76d9b5b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.cpp @@ -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 index 0000000..55f4955 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAKeyPair.h @@ -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 index 0000000..f600230 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +// 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 ber = Botan::PKCS8::BER_encode(*rsa); +#else + const Botan::SecureVector 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 keydata; +#else + Botan::SecureVector keydata; +#endif + Botan::AlgorithmIdentifier alg_id; + Botan::RSA_PrivateKey* key = NULL; + try + { + + Botan::BER_Decoder(source) + .start_cons(Botan::SEQUENCE) + .decode_and_check(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 index 0000000..7664a86 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAPrivateKey.h @@ -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 + +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 index 0000000..63bc82c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.cpp @@ -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 + +// 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 index 0000000..a0c0026 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSAPublicKey.h @@ -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 + +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 index 0000000..35846ec --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA1.cpp @@ -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 + +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 index 0000000..ca336b0 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA1.h @@ -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 + +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 index 0000000..f1d2268 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA224.cpp @@ -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 + +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 index 0000000..61fe16c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA224.h @@ -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 + +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 index 0000000..878dece --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA256.cpp @@ -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 + +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 index 0000000..5561f3c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA256.h @@ -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 + +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 index 0000000..b7a1e09 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA384.cpp @@ -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 + +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 index 0000000..5cf5d98 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA384.h @@ -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 + +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 index 0000000..b7aa459 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA512.cpp @@ -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 + +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 index 0000000..d72416e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSHA512.h @@ -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 + +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 index 0000000..3f13892 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.cpp @@ -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 + +#include +#include +#include + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,14) +#include +#endif + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0) +#include "Botan_ecb.h" +#include +#endif + +#ifdef WITH_AES_GCM +#include +#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 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 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 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 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 index 0000000..3031094 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanSymmetricAlgorithm.h @@ -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 +#include "config.h" +#include "SymmetricKey.h" +#include "SymmetricAlgorithm.h" + +#include +#include + +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 index 0000000..e5da460 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanUtil.cpp @@ -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 +#include +#include +#include + +// 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 der = ecGroup.DER_encode(Botan::EC_DOMPAR_ENC_OID); +#else + Botan::SecureVector 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 der(byteString.size()); + memcpy(&der[0], byteString.const_byte_str(), byteString.size()); + return Botan::EC_Group(der); +#else + return Botan::EC_Group(Botan::MemoryVector(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 repr = Botan::EC2OSP(ecPoint, Botan::PointGFp::UNCOMPRESSED); + Botan::secure_vector der; +#else + Botan::SecureVector repr = Botan::EC2OSP(ecPoint, Botan::PointGFp::UNCOMPRESSED); + Botan::SecureVector 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 repr; +#else + Botan::SecureVector 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 index 0000000..67f6ca6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanUtil.h @@ -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 +#if defined(WITH_ECC) || defined(WITH_GOST) +#include +#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 index 0000000..f27276e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/Botan_ecb.cpp @@ -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 +#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& 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& 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 index 0000000..1712083 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/Botan_ecb.h @@ -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 +#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 +#include +#include + +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 m_cipher; + std::unique_ptr 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& 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& 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 index 0000000..fbad3ae --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/Botan_rounding.h @@ -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 +#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 +#include + +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 +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 index 0000000..c676676 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/CryptoFactory.cpp @@ -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 index 0000000..761e473 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/CryptoFactory.h @@ -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 index 0000000..1d5f9bc --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DESKey.cpp @@ -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 index 0000000..895e4fa --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DESKey.h @@ -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 index 0000000..919901b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHParameters.cpp @@ -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 + +// 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 index 0000000..e0c963f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHParameters.h @@ -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 index 0000000..41103f1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHPrivateKey.cpp @@ -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 + +// 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 index 0000000..2c625da --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHPrivateKey.h @@ -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 index 0000000..17e041d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHPublicKey.cpp @@ -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 + +// 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 index 0000000..a070eb8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DHPublicKey.h @@ -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 index 0000000..79ef671 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAParameters.cpp @@ -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 + +// 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 index 0000000..978bc09 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAParameters.h @@ -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 index 0000000..1bdfd2d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAPrivateKey.cpp @@ -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 + +// 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 index 0000000..3b2070f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAPrivateKey.h @@ -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 index 0000000..4439bdd --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAPublicKey.cpp @@ -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 + +// 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 index 0000000..6d41e5d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/DSAPublicKey.h @@ -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 index 0000000..c4a6cfa --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECParameters.cpp @@ -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 + +// 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 index 0000000..76ca3e8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECParameters.h @@ -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 index 0000000..f132f2e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECPrivateKey.cpp @@ -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 + +// 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 index 0000000..0814181 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECPrivateKey.h @@ -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 index 0000000..a92d137 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECPublicKey.cpp @@ -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 + +// 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 index 0000000..ce6cf63 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/ECPublicKey.h @@ -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 index 0000000..9d23855 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.cpp @@ -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 + +// 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 index 0000000..929ddb1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/GOSTPrivateKey.h @@ -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 index 0000000..ad94068 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/GOSTPublicKey.cpp @@ -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 + +// 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 index 0000000..28de7b8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/GOSTPublicKey.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 index 0000000..934a64c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/HashAlgorithm.cpp @@ -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 index 0000000..ca2ae08 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/HashAlgorithm.h @@ -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 index 0000000..e100dc1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/MacAlgorithm.cpp @@ -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 +#include + +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 index 0000000..e9b22b0 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/MacAlgorithm.h @@ -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 +#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 index 0000000..f65e0a4 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/Makefile.am @@ -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 index 0000000..fd92a3e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLAES.cpp @@ -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 +#include +#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 index 0000000..6310f31 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLAES.h @@ -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 +#include +#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 index 0000000..554c308 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLCMAC.cpp @@ -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 index 0000000..8d15e7c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLCMAC.h @@ -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 + +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 index 0000000..ede710b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLComp.cpp @@ -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 + +#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 +#include +#include +#include +#include +#ifdef WITH_ECC +#include +#endif +#include + +#include + +// 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 index 0000000..4bced32 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLComp.h @@ -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 + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + +#include +#include +#include +#include +#ifdef WITH_ECC +#include +#endif +#include + +// 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 index 0000000..ad27482 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#ifdef WITH_GOST +#include +#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 index 0000000..e8bfa2c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLCryptoFactory.h @@ -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 +#ifdef WITH_GOST +#include +#include +#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 instance; +#else + static std::auto_ptr 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 index 0000000..4fb56b5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDES.cpp @@ -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 +#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 index 0000000..1ecdc8c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDES.h @@ -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 +#include +#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 index 0000000..ee61733 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDH.cpp @@ -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 +#include +#include +#include + +// 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 index 0000000..d611aee --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDH.h @@ -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 + +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 index 0000000..4865553 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.cpp @@ -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 index 0000000..320d5ab --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHKeyPair.h @@ -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 index 0000000..5571a88 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.cpp @@ -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 +#include +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..2cf8599 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHPrivateKey.h @@ -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 + +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 index 0000000..e261726 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.cpp @@ -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 +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..9f5eed8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDHPublicKey.h @@ -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 + +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 index 0000000..06b5d50 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp @@ -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 +#include +#include +#include + +// 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 index 0000000..1fb2b1e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSA.h @@ -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 + +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 index 0000000..aba56f1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.cpp @@ -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 index 0000000..6a0bdf2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAKeyPair.h @@ -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 index 0000000..527e041 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.cpp @@ -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 +#include +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..0e7a9ef --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAPrivateKey.h @@ -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 + +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 index 0000000..38ecc79 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.cpp @@ -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 +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..b30d05c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLDSAPublicKey.h @@ -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 + +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 index 0000000..e2abaeb --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECDH.cpp @@ -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 +#include +#include +#include +#ifdef WITH_FIPS +#include +#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 index 0000000..2cafa6f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECDH.h @@ -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 + +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 index 0000000..7387367 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp @@ -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 +#include +#include +#include +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..992fa40 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECDSA.h @@ -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 + +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 index 0000000..2e55f8f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.cpp @@ -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 index 0000000..ada9b8d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECKeyPair.h @@ -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 index 0000000..4f6b055 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.cpp @@ -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 +#include + +// 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 index 0000000..152ad03 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECPrivateKey.h @@ -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 +#include + +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 index 0000000..b2d80af --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.cpp @@ -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 +#include + +// 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 index 0000000..3fb4f35 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLECPublicKey.h @@ -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 + +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 index 0000000..27e29d9 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.cpp @@ -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 + +// 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 index 0000000..621e995 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPCMacAlgorithm.h @@ -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 +#include "config.h" +#include "SymmetricKey.h" +#include "MacAlgorithm.h" +#include +#include + +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 index 0000000..a1b4f73 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.cpp @@ -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 index 0000000..1775df2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPHashAlgorithm.h @@ -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 + +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 index 0000000..960b341 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.cpp @@ -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 index 0000000..69e3f18 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPMacAlgorithm.h @@ -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 +#include "config.h" +#include "SymmetricKey.h" +#include "MacAlgorithm.h" +#include +#include + +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 index 0000000..d43e741 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.cpp @@ -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 + +// 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 index 0000000..66bbeef --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLEVPSymmetricAlgorithm.h @@ -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 +#include +#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 index 0000000..4f34d45 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOST.cpp @@ -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 +#include +#include +#include +#include + +// 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 index 0000000..ad399f1 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOST.h @@ -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 + +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 index 0000000..969a216 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.cpp @@ -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 index 0000000..b064704 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTKeyPair.h @@ -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 index 0000000..6371e8f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.cpp @@ -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 +#include + +// 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 index 0000000..eca0f13 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTPrivateKey.h @@ -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 + +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 index 0000000..5810637 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.cpp @@ -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 +#include + +// 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 index 0000000..c951962 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTPublicKey.h @@ -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 + +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 index 0000000..5361075 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.cpp @@ -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 + +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 index 0000000..8175258 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLGOSTR3411.h @@ -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 + +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 index 0000000..f8b73a7 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLHMAC.cpp @@ -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 index 0000000..852614e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLHMAC.h @@ -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 + +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 index 0000000..2c962a6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLMD5.cpp @@ -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 + +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 index 0000000..22d7111 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLMD5.h @@ -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 + +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 index 0000000..d6a1e5d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRNG.cpp @@ -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 + +// 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 index 0000000..829f593 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRNG.h @@ -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 index 0000000..1e5638a --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSA.cpp @@ -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 +#include +#include +#include + +// 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 index 0000000..5b7db6d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSA.h @@ -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 + +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 index 0000000..6465d9c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.cpp @@ -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 index 0000000..546ba96 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAKeyPair.h @@ -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 index 0000000..26065cf --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.cpp @@ -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 +#include +#ifdef WITH_FIPS +#include +#endif +#include + +// 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 index 0000000..bb876d5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAPrivateKey.h @@ -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 + +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 index 0000000..2a6893b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.cpp @@ -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 +#include +#ifdef WITH_FIPS +#include +#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 index 0000000..98f99f2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLRSAPublicKey.h @@ -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 + +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 index 0000000..fcee390 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA1.cpp @@ -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 + +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 index 0000000..011803b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA1.h @@ -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 + +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 index 0000000..7dacf56 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA224.cpp @@ -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 + +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 index 0000000..f83ddf7 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA224.h @@ -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 + +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 index 0000000..d8b57b0 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA256.cpp @@ -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 + +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 index 0000000..1f22386 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA256.h @@ -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 + +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 index 0000000..01b6fce --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA384.cpp @@ -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 + +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 index 0000000..9b93724 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA384.h @@ -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 + +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 index 0000000..4533354 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA512.cpp @@ -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 + +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 index 0000000..cb266d8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLSHA512.h @@ -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 + +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 index 0000000..981bb98 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLUtil.cpp @@ -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 +#include + +// 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 index 0000000..f353cc6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/OSSLUtil.h @@ -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 +#ifdef WITH_ECC +#include +#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 index 0000000..cb14539 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/PrivateKey.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 + +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 index 0000000..2207e8d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/PublicKey.h @@ -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 index 0000000..ea0548f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RNG.h @@ -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 index 0000000..26ba7a7 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAParameters.cpp @@ -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 + +// 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 index 0000000..c8e748e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAParameters.h @@ -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 index 0000000..7b3d43d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAPrivateKey.cpp @@ -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 + +// 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 index 0000000..3c40c3c --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAPrivateKey.h @@ -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 index 0000000..e0e05cd --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAPublicKey.cpp @@ -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 + +// 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 index 0000000..9256966 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/RSAPublicKey.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 index 0000000..1db8f50 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.cpp @@ -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 +#include + +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 index 0000000..7e060c4 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/SymmetricAlgorithm.h @@ -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 +#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 index 0000000..550a144 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/SymmetricKey.cpp @@ -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 index 0000000..593040b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/SymmetricKey.h @@ -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 index 0000000..0ab2997 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/odd.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 index 0000000..008560f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/AESTests.cpp @@ -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 +#include +#include "AESTests.h" +#include "CryptoFactory.h" +#include "AESKey.h" +#include + +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 index 0000000..3a50b11 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/AESTests.h @@ -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 +#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 index 0000000..bcb1c6b --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DESTests.cpp @@ -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 +#include +#include "DESTests.h" +#include "CryptoFactory.h" +#include "DESKey.h" +#include + +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 index 0000000..0834462 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DESTests.h @@ -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 +#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 index 0000000..354cdac --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DHTests.cpp @@ -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 +#include +#include +#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 keySizes; + keySizes.push_back(1024); + + for (std::vector::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 keySizes; + keySizes.push_back(1024); + + for (std::vector::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 index 0000000..e2a58ac --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DHTests.h @@ -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 +#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 index 0000000..80f2514 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DSATests.cpp @@ -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 +#include +#include +#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 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::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 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 mechanisms; + mechanisms.push_back(AsymMech::DSA_SHA1); + mechanisms.push_back(AsymMech::DSA_SHA224); + mechanisms.push_back(AsymMech::DSA_SHA256); + + for (std::vector::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::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 index 0000000..446733a --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/DSATests.h @@ -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 +#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 index 0000000..1646fd8 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ECDHTests.cpp @@ -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 +#include +#include +#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 curves; + // Add X9.62 prime256v1 + curves.push_back(ByteString("06082a8648ce3d030107")); + // Add secp384r1 + curves.push_back(ByteString("06052b81040022")); + + for (std::vector::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 curves; + // Add X9.62 prime256v1 + curves.push_back(ByteString("06082a8648ce3d030107")); + // Add secp384r1 + curves.push_back(ByteString("06052b81040022")); + + for (std::vector::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) 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 index 0000000..81cf6d5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ECDHTests.h @@ -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 +#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 index 0000000..3c29d06 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ECDSATests.cpp @@ -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 +#include +#include +#include +#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 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::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 > 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 >::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) 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) 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 index 0000000..70b3345 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ECDSATests.h @@ -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 +#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 index 0000000..91f6876 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/GOSTTests.cpp @@ -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 +#include +#include "GOSTTests.h" +#include "CryptoFactory.h" +#include +#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 index 0000000..f243392 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/GOSTTests.h @@ -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 +#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 index 0000000..f02adbc --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/HashTests.cpp @@ -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 +#include +#include "HashTests.h" +#include "CryptoFactory.h" +#include +#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 index 0000000..dd6566d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/HashTests.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + HashTests.h + + Contains test cases to test the hash implementations + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_HASHTESTS_H +#define _SOFTHSM_V2_HASHTESTS_H + +#include +#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 index 0000000..8a3db1e --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/MacTests.cpp @@ -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 +#include +#include "MacTests.h" +#include "CryptoFactory.h" +#include +#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 index 0000000..9e6fa99 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/MacTests.h @@ -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 +#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 index 0000000..bf63ae6 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/Makefile.am @@ -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 index 0000000..da793b5 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/RNGTests.cpp @@ -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 +#include +#include "RNGTests.h" +#include "CryptoFactory.h" +#include "RNG.h" +#include "ent.h" +#include + +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 index 0000000..1391d81 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/RNGTests.h @@ -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 +#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 index 0000000..6af1e19 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/RSATests.cpp @@ -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 +#include +#include +#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 exponents; + exponents.push_back("010001"); + exponents.push_back("03"); + exponents.push_back("0B"); + exponents.push_back("11"); + + // Key sizes to test + std::vector 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::iterator e = exponents.begin(); e != exponents.end(); e++) + { + for (std::vector::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 exponents; + exponents.push_back("010001"); + exponents.push_back("03"); + exponents.push_back("0B"); + exponents.push_back("11"); + + // Key sizes to test + std::vector keySizes; + keySizes.push_back(1024); + keySizes.push_back(1280); + keySizes.push_back(2048); + //keySizes.push_back(4096); + + // Mechanisms to test + std::vector 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::iterator e = exponents.begin(); e != exponents.end(); e++) + { + for (std::vector::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::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 exponents; + exponents.push_back("010001"); + exponents.push_back("03"); + exponents.push_back("0B"); + exponents.push_back("11"); + + // Key sizes to test + std::vector keySizes; + keySizes.push_back(1024); + keySizes.push_back(1280); + keySizes.push_back(2048); + //keySizes.push_back(4096); + + // Paddings to test + std::vector paddings; + paddings.push_back(AsymMech::RSA_PKCS); + paddings.push_back(AsymMech::RSA_PKCS_OAEP); + paddings.push_back(AsymMech::RSA); + + for (std::vector::iterator e = exponents.begin(); e != exponents.end(); e++) + { + for (std::vector::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::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 index 0000000..ca5c86d --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/RSATests.h @@ -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 +#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 index 0000000..3fe4f66 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/chisq.c @@ -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 + +/*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 index 0000000..2fc7b8f --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/cryptotest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + cryptotest.cpp + + The main test executor for tests on the cryptographic functions in SoftHSM v2 + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#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::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr BotanCryptoFactory::instance(NULL); +#endif + +#endif + +int main(int /*argc*/, char** /*argv*/) +{ + CppUnit::TestResult controller; + CppUnit::TestResultCollector result; + CppUnit::TextUi::TestRunner runner; + controller.addListener(&result); + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/SoftHSMv2/src/lib/crypto/test/ent.c b/SoftHSMv2/src/lib/crypto/test/ent.c new file mode 100644 index 0000000..b255405 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ent.c @@ -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 +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#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 index 0000000..5958888 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/ent.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 index 0000000..bed7244 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/iso8859.c @@ -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 index 0000000..7462f15 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/iso8859.h @@ -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 index 0000000..5a54737 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/randtest.c @@ -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 + +#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 index 0000000..53bef35 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/test/randtest.h @@ -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 index 0000000..e133f71 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/ByteString.cpp @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ByteString.cpp + + A string class for byte strings stored in securely allocated memory + *****************************************************************************/ + +#include +#include +#include +#include "config.h" +#include "log.h" +#include "ByteString.h" + +// Constructors +ByteString::ByteString() +{ +} + +ByteString::ByteString(const unsigned char* bytes, const size_t bytesLen) +{ + byteString.resize(bytesLen); + + if (bytesLen > 0) + memcpy(&byteString[0], bytes, bytesLen); +} + +ByteString::ByteString(const char* hexString) +{ + std::string hex = std::string(hexString); + + if (hex.size() % 2 != 0) + { + hex = "0" + hex; + } + + for (size_t i = 0; i < hex.size(); i += 2) + { + std::string byteStr; + byteStr += hex[i]; + byteStr += hex[i+1]; + + unsigned char byteVal = (unsigned char) strtoul(byteStr.c_str(), NULL, 16); + + this->operator+=(byteVal); + } +} + +ByteString::ByteString(const unsigned long longValue) +{ + unsigned long setValue = longValue; + + // Convert the value to a big-endian byte string; N.B.: this code assumes that unsigned long + // values are stored as a 64-bit value, which is a safe assumption on modern systems. It will + // also properly handle a 32-bit value and will simply store 4 zeroes at the front of the + // string. If at some point in time we get 128-bit architectures, the top 8 bytes of the value + // will be discarded... (but hey, 640K is enough for everybody, right?) + // + // The reason for coding it this way is that implementations of SoftHSM will maintain + // binary compatibility between eachothers background storage (i.e. a 32-bit SoftHSM version can + // read the storage of a 64-bit version and vice versa under the assumption that the stored + // values never exceed 32-bits, which is likely since these values are only used to encode + // byte string lengths) + unsigned char byteStrIn[8]; + + for (size_t i = 0; i < 8; i++) + { + byteStrIn[7-i] = (unsigned char) (setValue & 0xFF); + setValue >>= 8; + } + + byteString.resize(8); + memcpy(&byteString[0], byteStrIn, 8); +} + +ByteString::ByteString(const ByteString& in) +{ + this->byteString = in.byteString; +} + +// Append data +ByteString& ByteString::operator+=(const ByteString& append) +{ + size_t curLen = byteString.size(); + size_t toAdd = append.byteString.size(); + size_t newLen = curLen + toAdd; + + byteString.resize(newLen); + + if (toAdd > 0) + memcpy(&byteString[curLen], &append.byteString[0], toAdd); + + return *this; +} + +ByteString& ByteString::operator+=(const unsigned char byte) +{ + byteString.push_back(byte); + + return *this; +} + +// XORing +ByteString& ByteString::operator^=(const ByteString& rhs) +{ + size_t xorLen = std::min(this->size(), rhs.size()); + + for (size_t i = 0; i < xorLen; i++) + { + byteString[i] ^= rhs.const_byte_str()[i]; + } + + return *this; +} + +// Return a substring +ByteString ByteString::substr(const size_t start, const size_t len /* = SIZE_T_MAX */) const +{ + size_t retLen = std::min(len, byteString.size() - start); + + if (start >= byteString.size()) + { + return ByteString(); + } + else + { + return ByteString(&byteString[start], retLen); + } +} + +// Add data +ByteString operator+(const ByteString& lhs, const ByteString& rhs) +{ + ByteString rv = lhs; + rv += rhs; + + return rv; +} + +ByteString operator+(const unsigned char lhs, const ByteString& rhs) +{ + ByteString rv(&lhs, 1); + rv += rhs; + + return rv; +} + +ByteString operator+(const ByteString& lhs, const unsigned char rhs) +{ + ByteString rv = lhs; + rv += rhs; + + return rv; +} + +// Array operator +unsigned char& ByteString::operator[](size_t pos) +{ + return byteString[pos]; +} + +// Return the byte string data +unsigned char* ByteString::byte_str() +{ + return &byteString[0]; +} + +// Return the const byte string +const unsigned char* ByteString::const_byte_str() const +{ + return (const unsigned char*) &byteString[0]; +} + +// Return a hexadecimal character representation of the string +std::string ByteString::hex_str() const +{ + std::string rv; + char hex[3]; + + for (size_t i = 0; i < byteString.size(); i++) + { + sprintf(hex, "%02X", byteString[i]); + + rv += hex; + } + + return rv; +} + +// Return the long value +unsigned long ByteString::long_val() const +{ + // Convert the first 8 bytes of the string to an unsigned long value + unsigned long rv = 0; + + for (size_t i = 0; i < std::min(size_t(8), byteString.size()); i++) + { + rv <<= 8; + rv += byteString[i]; + } + + return rv; +} + +// Cut of the first part of the string and convert it to a long value +unsigned long ByteString::firstLong() +{ + unsigned long rv = long_val(); + + split(8); + + return rv; +} + +// Split of the specified part of the string as a separate byte string +ByteString ByteString::split(size_t len) +{ + ByteString rv = substr(0, len); + + size_t newSize = (byteString.size() > len) ? (byteString.size() - len) : 0; + + if (newSize > 0) + { + for (size_t i = 0; i < newSize; i++) + { + byteString[i] = byteString[i + len]; + } + } + + byteString.resize(newSize); + + return rv; +} + +// The size of the byte string in bits +size_t ByteString::bits() const +{ + size_t bits = byteString.size() * 8; + + if (bits == 0) return 0; + + for (size_t i = 0; i < byteString.size(); i++) + { + unsigned char byte = byteString[i]; + + for (unsigned char mask = 0x80; mask > 0; mask >>= 1) + { + if ((byte & mask) == 0) + { + bits--; + } + else + { + return bits; + } + } + } + + return bits; +} + +// The size of the byte string in bytes +size_t ByteString::size() const +{ + return byteString.size(); +} + +void ByteString::resize(const size_t newSize) +{ + byteString.resize(newSize); +} + +void ByteString::wipe(const size_t newSize /* = 0 */) +{ + this->resize(newSize); + + if (!byteString.empty()) + memset(&byteString[0], 0x00, byteString.size()); +} + +// Comparison +bool ByteString::operator==(const ByteString& compareTo) const +{ + if (compareTo.size() != this->size()) + { + return false; + } + else if (this->size() == 0) + { + return true; + } + + return (memcmp(&byteString[0], &compareTo.byteString[0], this->size()) == 0); +} + +bool ByteString::operator!=(const ByteString& compareTo) const +{ + if (compareTo.size() != this->size()) + { + return true; + } + else if (this->size() == 0) + { + return false; + } + + return (memcmp(&byteString[0], &compareTo.byteString[0], this->size()) != 0); +} + +// XOR data +ByteString operator^(const ByteString& lhs, const ByteString& rhs) +{ + size_t xorLen = std::min(lhs.size(), rhs.size()); + ByteString rv; + + for (size_t i = 0; i < xorLen; i++) + { + rv += lhs.const_byte_str()[i] ^ rhs.const_byte_str()[i]; + } + + return rv; +} + +// Serialisation/deserialisation +ByteString ByteString::serialise() const +{ + ByteString len((unsigned long) size()); + + return len + *this; +} + +/* static */ ByteString ByteString::chainDeserialise(ByteString& serialised) +{ + size_t len = (size_t) serialised.firstLong(); + + ByteString rv = serialised.split(len); + + return rv; +} + diff --git a/SoftHSMv2/src/lib/data_mgr/ByteString.h b/SoftHSMv2/src/lib/data_mgr/ByteString.h new file mode 100644 index 0000000..2c2ef33 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/ByteString.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ByteString.h + + A string class for byte strings stored in securely allocated memory + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_BYTESTRING_H +#define _SOFTHSM_V2_BYTESTRING_H + +#include +#include +#include +#include +#include +#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 > byteString; +}; + +// Add data +ByteString operator+(const ByteString& lhs, const ByteString& rhs); +ByteString operator+(const unsigned char lhs, const ByteString& rhs); +ByteString operator+(const ByteString& lhs, const unsigned char rhs); + +// XOR data +ByteString operator^(const ByteString& lhs, const ByteString& rhs); + +#endif // !_SOFTHSM_V2_BYTESTRING_H + diff --git a/SoftHSMv2/src/lib/data_mgr/Makefile.am b/SoftHSMv2/src/lib/data_mgr/Makefile.am new file mode 100644 index 0000000..85aa4d7 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/Makefile.am @@ -0,0 +1,17 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../crypto \ + -I$(srcdir)/../common \ + -I$(srcdir)/../pkcs11 + +noinst_LTLIBRARIES = libsofthsm_datamgr.la +libsofthsm_datamgr_la_SOURCES = ByteString.cpp \ + RFC4880.cpp \ + salloc.cpp \ + SecureDataManager.cpp \ + SecureMemoryRegistry.cpp + +SUBDIRS = test + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp b/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp new file mode 100644 index 0000000..9ea23bd --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + RFC4880.cpp + + Implements a secure password-based key derivation scheme. It is not a generic + implementation of the RFC but only generates 256-bit AES keys according to + the "iterated and salted" scheme. + *****************************************************************************/ + +#include "config.h" +#include "RFC4880.h" +#include "CryptoFactory.h" +#include "HashAlgorithm.h" + +// This function derives a 256-bit AES key from the supplied password data +bool RFC4880::PBEDeriveKey(const ByteString& password, ByteString& salt, AESKey** ppKey) +{ + // Check that a proper salt value was supplied; it should be at least 8 bytes long + if (salt.size() < 8) + { + ERROR_MSG("Insufficient salt data supplied for password-based encryption"); + + return false; + } + + // Check other parameters + if ((password.size() == 0) || (ppKey == NULL)) + { + return false; + } + + // Determine the iteration count based on the last byte of the salt + unsigned int iter = PBE_ITERATION_BASE_COUNT + salt[salt.size() - 1]; + + // Get a hash instance + HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256); + + if (hash == NULL) + { + ERROR_MSG("Could not get a SHA-256 instance"); + + return false; + } + + // Perform the first iteration which takes as input the salt value and + // the password + ByteString intermediate; + + if (!hash->hashInit() || + !hash->hashUpdate(salt) || + !hash->hashUpdate(password) || + !hash->hashFinal(intermediate)) + { + ERROR_MSG("Hashing failed"); + + CryptoFactory::i()->recycleHashAlgorithm(hash); + + return false; + } + + // Perform the remaining iteration + while (--iter > 0) + { + if (!hash->hashInit() || + !hash->hashUpdate(intermediate) || + !hash->hashFinal(intermediate)) + { + ERROR_MSG("Hashing failed"); + + CryptoFactory::i()->recycleHashAlgorithm(hash); + + return false; + } + } + + // Create the AES key instance + *ppKey = new AESKey(256); + (*ppKey)->setKeyBits(intermediate); + + // Release the hash instance + CryptoFactory::i()->recycleHashAlgorithm(hash); + + return true; +} + diff --git a/SoftHSMv2/src/lib/data_mgr/RFC4880.h b/SoftHSMv2/src/lib/data_mgr/RFC4880.h new file mode 100644 index 0000000..7967ef6 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/RFC4880.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + RFC4880.h + + Implements a secure password-based key derivation scheme. It is not a generic + implementation of the RFC but only generates 256-bit AES keys according to + the "iterated and salted" scheme. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_RFC4880_H +#define _SOFTHSM_V2_RFC4880_H + +#include "config.h" +#include "ByteString.h" +#include "log.h" +#include "AESKey.h" + +// This define sets the base PBE iteration count; the lowest byte of the salt is added +// to this value as a form of jitter +#define PBE_ITERATION_BASE_COUNT 1500 + +namespace RFC4880 +{ + // This function derives a 256-bit AES key from the supplied password data + bool PBEDeriveKey(const ByteString& password, ByteString& salt, AESKey** ppKey); +} + +#endif // !_SOFTHSM_V2_RFC4880_H + diff --git a/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h b/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h new file mode 100644 index 0000000..71dc80c --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureAllocator.h + + Implements a template class for a secure C++ allocator. The allocator will + zero all the memory it allocates before releasing it to ensure that the + data stored in the memory is destroyed properly to minimise the risk of + obtaining sensitive data from memory + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SECUREALLOCATOR_H +#define _SOFTHSM_V2_SECUREALLOCATOR_H + +#include +#include +#include +#if defined(SENSITIVE_NON_PAGED) && !defined(_WIN32) +#include +#endif // SENSITIVE_NON_PAGED +#include "config.h" +#include "log.h" +#include "SecureMemoryRegistry.h" + +template 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 struct rebind + { + typedef SecureAllocator other; + }; + + // Constructor + inline SecureAllocator() { } + + inline SecureAllocator(const SecureAllocator&) { } + + template SecureAllocator(const SecureAllocator&) { } + + // Destructor + inline virtual ~SecureAllocator() { } + + // Return the maximum allocation size + size_type max_size() const + { + return std::numeric_limits::max() / sizeof(T); + } + + // Return the address of values + inline pointer address(reference value) const + { + return &value; + } + + inline const_pointer address(const_reference value) const + { + return &value; + } + + // Allocate n elements of type T + inline pointer allocate(size_type n, const void* = NULL) + { +#ifdef SENSITIVE_NON_PAGED + // Allocate memory on a page boundary +#ifndef _WIN32 + pointer r = (pointer) valloc(n * sizeof(T)); +#else + pointer r = (pointer) VirtualAlloc(NULL, n * sizeof(T), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif + + if (r == NULL) + { + ERROR_MSG("Out of memory"); + + return NULL; + } + + // Lock the memory so it doesn't get swapped out +#ifndef _WIN32 + if (mlock((const void*) r, n * sizeof(T)) != 0) +#else + if (VirtualLock((const void*) r, n * sizeof(T)) == 0) +#endif + { + ERROR_MSG("Could not allocate non-paged memory for secure storage"); + + // Hmmm... best to not return any allocated space in this case +#ifndef _WIN32 + free(r); +#else + VirtualFree((const void*) r, MEM_RELEASE); +#endif + + return NULL; + } + + // Register the memory in the secure memory registry + SecureMemoryRegistry::i()->add(r, n * sizeof(T)); + + return r; +#else + pointer r = (pointer)(::operator new(n * sizeof(T))); + + if (r == NULL) + { + ERROR_MSG("Out of memory"); + + return NULL; + } + + // Register the memory in the secure memory registry + SecureMemoryRegistry::i()->add(r, n * sizeof(T)); + + return r; +#endif // SENSITIVE_NON_PAGED + } + + // Deallocate n elements of type T + inline void deallocate(pointer p, size_type n) + { +#ifdef PARANOID + // First toggle all bits on + memset(p, 0xFF, n * sizeof(T)); +#endif // PARANOID + + // Toggle all bits off + memset(p, 0x00, n * sizeof(T)); + + // Unregister the memory from the secure memory registry + SecureMemoryRegistry::i()->remove(p); + +#ifdef SENSITIVE_NON_PAGED +#ifndef _WIN32 + munlock((const void*) p, n * sizeof(T)); +#else + VirtualUnlock((const void*) p, n * sizeof(T)); +#endif + +#ifndef _WIN32 + free(p); +#else + VirtualFree((const void*) r, MEM_RELEASE); +#endif +#else + // Release the memory + ::operator delete((void*) p); +#endif // SENSITIVE_NON_PAGED + } + + // Initialise allocate storage with a value + void construct(pointer p, const T& value) + { + new((void*) p)T(value); + } + + // Destroy elements of initialised storage + void destroy(pointer p) + { + // Call destructor + p->~T(); + } + + // Comparison operators + inline bool operator==(SecureAllocator const&) const { return true; } + inline bool operator!=(SecureAllocator const&) const { return false; } +}; + +#endif // !_SOFTHSM_V2_SECUREALLOCATOR_H + diff --git a/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp new file mode 100644 index 0000000..987e76b --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureDataManager.cpp + + The secure data manager main class. Every token instance has a secure data + manager instance member that is used to decrypt and encrypt sensitive object + attributes such as key material. The secure data manager maintains a key blob + containing a 256-bit AES key that is used in this decryption and encryption + process. The key blob itself is encrypted using a PBE derived key that is + derived from the user PIN and a PBE key that is derived from the SO PIN. It + is up to the token to enforce access control based on which user is logged + in; authentication using the SO PIN is required to be able to change the + user PIN. The master key that is used to decrypt/encrypt sensitive attributes + is stored in memory under a mask that is changed every time the key is used. + *****************************************************************************/ + +#include "config.h" +#include "SecureDataManager.h" +#include "CryptoFactory.h" +#include "AESKey.h" +#include "SymmetricAlgorithm.h" +#include "RFC4880.h" + +// Constructors + +// Initialise the object; called by all constructors +void SecureDataManager::initObject() +{ + // Get an RNG instance + rng = CryptoFactory::i()->getRNG(); + + // Get an AES implementation + aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES); + + // Initialise masking data + mask = new ByteString(); + + rng->generateRandom(*mask, 32); + + // Set the initial login state + soLoggedIn = userLoggedIn = false; + + // Set the magic + magic = ByteString("524A52"); // RJR + + // Get a mutex + dataMgrMutex = MutexFactory::i()->getMutex(); +} + +// Constructs a new SecureDataManager for a blank token; actual +// initialisation is done by setting the SO PIN +SecureDataManager::SecureDataManager() +{ + initObject(); +} + +// Constructs a SecureDataManager using the specified key blob +SecureDataManager::SecureDataManager(const ByteString& soPINBlob, const ByteString& userPINBlob) +{ + initObject(); + + // De-serialise the key blob + soEncryptedKey = soPINBlob; + userEncryptedKey = userPINBlob; +} + +// Destructor +SecureDataManager::~SecureDataManager() +{ + // Recycle the AES instance + CryptoFactory::i()->recycleSymmetricAlgorithm(aes); + + // Clean up the mask + delete mask; + + MutexFactory::i()->recycleMutex(dataMgrMutex); +} + +// Generic function for creating an encrypted version of the key from the specified passphrase +bool SecureDataManager::pbeEncryptKey(const ByteString& passphrase, ByteString& encryptedKey) +{ + // Generate salt + ByteString salt; + + if (!rng->generateRandom(salt, 8)) return false; + + // Derive the key using RFC4880 PBE + AESKey* pbeKey = NULL; + + if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey)) + { + return false; + } + + // Add the salt + encryptedKey.wipe(); + encryptedKey += salt; + + // Generate random IV + ByteString IV; + + if (!rng->generateRandom(IV, aes->getBlockSize())) return false; + + // Add the IV + encryptedKey += IV; + + // Encrypt the data + ByteString block; + + if (!aes->encryptInit(pbeKey, SymMode::CBC, IV)) + { + delete pbeKey; + + return false; + } + + // First, add the magic + if (!aes->encryptUpdate(magic, block)) + { + delete pbeKey; + + return false; + } + + encryptedKey += block; + + // Then, add the key itself + ByteString key; + + { + MutexLocker lock(dataMgrMutex); + + unmask(key); + + bool rv = aes->encryptUpdate(key, block); + + remask(key); + + if (!rv) + { + delete pbeKey; + + return false; + } + } + + encryptedKey += block; + + // And finalise encryption + if (!aes->encryptFinal(block)) + { + delete pbeKey; + + return false; + } + + encryptedKey += block; + + delete pbeKey; + + return true; +} + +// Set the SO PIN (requires either a blank SecureDataManager or the +// SO to have logged in previously) +bool SecureDataManager::setSOPIN(const ByteString& soPIN) +{ + // Check the new PIN + if (soPIN.size() == 0) + { + DEBUG_MSG("Zero length PIN specified"); + + return false; + } + + // Check if the SO needs to be logged in + if ((soEncryptedKey.size() > 0) && !soLoggedIn) + { + DEBUG_MSG("SO must be logged in to change the SO PIN"); + + return false; + } + + // If no SO PIN was set, then this is a SecureDataManager for a blank token. This + // means a new key has to be generated + if (soEncryptedKey.size() == 0) + { + ByteString key; + + rng->generateRandom(key, 32); + + remask(key); + } + + return pbeEncryptKey(soPIN, soEncryptedKey); +} + +// Set the user PIN (requires either the SO or the user to have logged +// in previously) +bool SecureDataManager::setUserPIN(const ByteString& userPIN) +{ + // Check if the SO or the user is logged in + if (!soLoggedIn && !userLoggedIn) + { + DEBUG_MSG("Must be logged in to change the user PIN"); + + return false; + } + + // Check the new PIN + if (userPIN.size() == 0) + { + DEBUG_MSG("Zero length PIN specified"); + + return false; + } + + return pbeEncryptKey(userPIN, userEncryptedKey); +} + +// Generic login function +bool SecureDataManager::login(const ByteString& passphrase, const ByteString& encryptedKey) +{ + // Log out first + this->logout(); + + // First, take the salt from the encrypted key + ByteString salt = encryptedKey.substr(0,8); + + // Then, take the IV from the encrypted key + ByteString IV = encryptedKey.substr(8, aes->getBlockSize()); + + // Now, take the encrypted data from the encrypted key + ByteString encryptedKeyData = encryptedKey.substr(8 + aes->getBlockSize()); + + // Derive the PBE key + AESKey* pbeKey = NULL; + + if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey)) + { + return false; + } + + // Decrypt the key data + ByteString decryptedKeyData; + ByteString finalBlock; + + // NOTE: The login will fail here if incorrect passphrase is supplied + if (!aes->decryptInit(pbeKey, SymMode::CBC, IV) || + !aes->decryptUpdate(encryptedKeyData, decryptedKeyData) || + !aes->decryptFinal(finalBlock)) + { + delete pbeKey; + + return false; + } + + delete pbeKey; + + decryptedKeyData += finalBlock; + + // Check the magic + if (decryptedKeyData.substr(0, 3) != magic) + { + // The passphrase was incorrect + DEBUG_MSG("Incorrect passphrase supplied"); + + return false; + } + + // Strip off the magic + ByteString key = decryptedKeyData.substr(3); + + // And mask the key + decryptedKeyData.wipe(); + + MutexLocker lock(dataMgrMutex); + remask(key); + + return true; +} + +// Log in using the SO PIN +bool SecureDataManager::loginSO(const ByteString& soPIN) +{ + return (soLoggedIn = login(soPIN, soEncryptedKey)); +} + +// Log in using the user PIN +bool SecureDataManager::loginUser(const ByteString& userPIN) +{ + return (userLoggedIn = login(userPIN, userEncryptedKey)); +} + +// Generic re-authentication function +bool SecureDataManager::reAuthenticate(const ByteString& passphrase, const ByteString& encryptedKey) +{ + // First, take the salt from the encrypted key + ByteString salt = encryptedKey.substr(0,8); + + // Then, take the IV from the encrypted key + ByteString IV = encryptedKey.substr(8, aes->getBlockSize()); + + // Now, take the encrypted data from the encrypted key + ByteString encryptedKeyData = encryptedKey.substr(8 + aes->getBlockSize()); + + // Derive the PBE key + AESKey* pbeKey = NULL; + + if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey)) + { + return false; + } + + // Decrypt the key data + ByteString decryptedKeyData; + ByteString finalBlock; + + // NOTE: The login will fail here if incorrect passphrase is supplied + if (!aes->decryptInit(pbeKey, SymMode::CBC, IV) || + !aes->decryptUpdate(encryptedKeyData, decryptedKeyData) || + !aes->decryptFinal(finalBlock)) + { + delete pbeKey; + + return false; + } + + delete pbeKey; + + decryptedKeyData += finalBlock; + + // Check the magic + if (decryptedKeyData.substr(0, 3) != magic) + { + // The passphrase was incorrect + DEBUG_MSG("Incorrect passphrase supplied"); + + return false; + } + + // And mask the key + decryptedKeyData.wipe(); + + return true; +} + +// Re-authenticate the SO +bool SecureDataManager::reAuthenticateSO(const ByteString& soPIN) +{ + return reAuthenticate(soPIN, soEncryptedKey); +} + +// Re-authenticate the user +bool SecureDataManager::reAuthenticateUser(const ByteString& userPIN) +{ + return reAuthenticate(userPIN, userEncryptedKey); +} + +// Log out +void SecureDataManager::logout() +{ + MutexLocker lock(dataMgrMutex); + + // Clear the logged in state + soLoggedIn = userLoggedIn = false; + + // Clear the masked key + maskedKey.wipe(); +} + +// Decrypt the supplied data +bool SecureDataManager::decrypt(const ByteString& encrypted, ByteString& plaintext) +{ + // Check the object logged in state + if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32)) + { + return false; + } + + // Do not attempt decryption of empty byte strings + if (encrypted.size() == 0) + { + plaintext = ByteString(""); + return true; + } + + AESKey theKey(256); + ByteString unmaskedKey; + + { + MutexLocker lock(dataMgrMutex); + + unmask(unmaskedKey); + + theKey.setKeyBits(unmaskedKey); + + remask(unmaskedKey); + } + + // Take the IV from the input data + ByteString IV = encrypted.substr(0, aes->getBlockSize()); + + if (IV.size() != aes->getBlockSize()) + { + ERROR_MSG("Invalid IV in encrypted data"); + + return false; + } + + ByteString finalBlock; + + if (!aes->decryptInit(&theKey, SymMode::CBC, IV) || + !aes->decryptUpdate(encrypted.substr(aes->getBlockSize()), plaintext) || + !aes->decryptFinal(finalBlock)) + { + return false; + } + + plaintext += finalBlock; + + return true; +} + +// Encrypt the supplied data +bool SecureDataManager::encrypt(const ByteString& plaintext, ByteString& encrypted) +{ + // Check the object logged in state + if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32)) + { + return false; + } + + AESKey theKey(256); + ByteString unmaskedKey; + + { + MutexLocker lock(dataMgrMutex); + + unmask(unmaskedKey); + + theKey.setKeyBits(unmaskedKey); + + remask(unmaskedKey); + } + + // Wipe encrypted data block + encrypted.wipe(); + + // Generate random IV + ByteString IV; + + if (!rng->generateRandom(IV, aes->getBlockSize())) return false; + + ByteString finalBlock; + + if (!aes->encryptInit(&theKey, SymMode::CBC, IV) || + !aes->encryptUpdate(plaintext, encrypted) || + !aes->encryptFinal(finalBlock)) + { + return false; + } + + encrypted += finalBlock; + + // Add IV to output data + encrypted = IV + encrypted; + + return true; +} + +// Returns the key blob for the SO PIN +ByteString SecureDataManager::getSOPINBlob() +{ + return soEncryptedKey; +} + +// Returns the key blob for the user PIN +ByteString SecureDataManager::getUserPINBlob() +{ + return userEncryptedKey; +} + +// Unmask the key +void SecureDataManager::unmask(ByteString& key) +{ + key = maskedKey; + key ^= *mask; +} + +// Remask the key +void SecureDataManager::remask(ByteString& key) +{ + // Generate a new mask + rng->generateRandom(*mask, 32); + + key ^= *mask; + maskedKey = key; +} + +// Check if the SO is logged in +bool SecureDataManager::isSOLoggedIn() +{ + return soLoggedIn; +} + +// Check if the user is logged in +bool SecureDataManager::isUserLoggedIn() +{ + return userLoggedIn; +} + diff --git a/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h new file mode 100644 index 0000000..93d99bc --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureDataManager.h + + The secure data manager main class. Every token instance has a secure data + manager instance member that is used to decrypt and encrypt sensitive object + attributes such as key material. The secure data manager maintains a key blob + containing a 256-bit AES key that is used in this decryption and encryption + process. The key blob itself is encrypted using a PBE derived key that is + derived from the user PIN and a PBE key that is derived from the SO PIN. It + is up to the token to enforce access control based on which user is logged + in; authentication using the SO PIN is required to be able to change the + user PIN. The master key that is used to decrypt/encrypt sensitive attributes + is stored in memory under a mask that is changed every time the key is used. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SECUREDATAMANAGER_H +#define _SOFTHSM_V2_SECUREDATAMANAGER_H + +#include "config.h" +#include "ByteString.h" +#include "log.h" +#include "AESKey.h" +#include "RNG.h" +#include "SymmetricAlgorithm.h" +#include "MutexFactory.h" + +class SecureDataManager +{ +public: + // Constructors + + // Constructs a new SecureDataManager for a blank token; actual + // initialisation is done by setting the SO PIN + SecureDataManager(); + + // Constructs a SecureDataManager using the specified SO PIN and user PIN + SecureDataManager(const ByteString& soPINBlob, const ByteString& userPINBlob); + + // Destructor + virtual ~SecureDataManager(); + + // Set the SO PIN (requires either a blank SecureDataManager or the + // SO to have logged in previously) + bool setSOPIN(const ByteString& soPIN); + + // Set the user PIN (requires either the SO or the user to have logged + // in previously) + bool setUserPIN(const ByteString& userPIN); + + // Log in using the SO PIN + bool loginSO(const ByteString& soPIN); + bool isSOLoggedIn(); + + // Log in using the user PIN + bool loginUser(const ByteString& userPIN); + bool isUserLoggedIn(); + + // Re-authentication + bool reAuthenticateSO(const ByteString& soPIN); + bool reAuthenticateUser(const ByteString& userPIN); + + // Log out + void logout(); + + // Decrypt the supplied data + bool decrypt(const ByteString& encrypted, ByteString& plaintext); + + // Encrypt the supplied data + bool encrypt(const ByteString& plaintext, ByteString& encrypted); + + // Returns the key blob for the SO PIN + ByteString getSOPINBlob(); + + // Returns the key blob for the user PIN + ByteString getUserPINBlob(); + +private: + // Initialise the object + void initObject(); + + // Generic login function + bool login(const ByteString& passphrase, const ByteString& encryptedKey); + + // Generic re-authentication function + bool reAuthenticate(const ByteString& passphrase, const ByteString& encryptedKey); + + // Generic function for creating an encrypted version of the key from the specified passphrase + bool pbeEncryptKey(const ByteString& passphrase, ByteString& encryptedKey); + + // Unmask the key + void unmask(ByteString& key); + + // Remask the key + void remask(ByteString& key); + + // The user PIN encrypted key + ByteString userEncryptedKey; + + // The SO PIN encrypted key + ByteString soEncryptedKey; + + // Which users are logged in + bool soLoggedIn; + bool userLoggedIn; + + // The masked version of the actual key + ByteString maskedKey; + + // The "magic" data used to detect if a PIN was likely to be correct + ByteString magic; + + // The mask; this is not a stack member but a heap member. This + // hopefully ensures that the mask ends up in a memory location + // that is not logically linked to the masked key + ByteString* mask; + + // Random number generator instance + RNG* rng; + + // AES instance + SymmetricAlgorithm* aes; + + // Mutex + Mutex* dataMgrMutex; +}; + +#endif // !_SOFTHSM_V2_SECUREDATAMANAGER_H + diff --git a/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp new file mode 100644 index 0000000..57de156 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureMemoryRegistry.cpp + + Implements a singleton class that keeps track of all securely allocated + memory. This registry can be used to wipe securely allocated memory in case + of a fatal exception + *****************************************************************************/ + +#include +#include +#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::iterator i = registry.begin(); i != registry.end(); i++) + { + try + { + DEBUG_MSG("Wiping block of %d bytes at 0x%x", i->second, i->first); + } + catch (...) + { + } + + try + { + #ifdef PARANOID + memset(i->first, 0xFF, i->second); + #endif // PARANOID + memset(i->first, 0x00, i->second); + } + catch (...) + { + ERROR_MSG("Failed to wipe block of %d bytes at 0x%x", i->second, i->first); + } + } + } + catch (...) + { + ERROR_MSG("Failed to enumerate the secure memory registry"); + } +} + diff --git a/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h new file mode 100644 index 0000000..6c73369 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureMemoryRegistry.h + + Implements a singleton class that keeps track of all securely allocated + memory. This registry can be used to wipe securely allocated memory in case + of a fatal exception + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SECUREMEMORYREGISTRY_H +#define _SOFTHSM_V2_SECUREMEMORYREGISTRY_H + +#include +#include +#include +#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 instance; +#else + static std::auto_ptr instance; +#endif + + std::map registry; + + Mutex* SecMemRegistryMutex; +}; + +#endif // !_SOFTHSM_V2_SECUREMEMORYREGISTRY_H + diff --git a/SoftHSMv2/src/lib/data_mgr/salloc.cpp b/SoftHSMv2/src/lib/data_mgr/salloc.cpp new file mode 100644 index 0000000..0bd4238 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/salloc.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + salloc.cpp + + Contains an implementation of malloc that allocates memory securely + *****************************************************************************/ + +#include "config.h" +#include "log.h" +#include "salloc.h" +#include +#if defined(SENSITIVE_NON_PAGED) && !defined(_WIN32) +#include +#endif // SENSITIVE_NON_PAGED +#include +#include "SecureMemoryRegistry.h" + +// Allocate memory +void* salloc(size_t len) +{ +#ifdef SENSITIVE_NON_PAGED + // Allocate memory on a page boundary +#ifndef _WIN32 + void* ptr = (void*) valloc(len); +#else + pointer r = (pointer) VirtualAlloc(NULL, n * sizeof(T), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif + + if (ptr == NULL) + { + ERROR_MSG("Out of memory"); + + return NULL; + } + + // Lock the memory so it doesn't get swapped out +#ifndef _WIN32 + if (mlock((const void*) ptr, len) != 0) +#else + if (VirtualLock((const void*) r, n * sizeof(T)) == 0) +#endif + { + ERROR_MSG("Could not allocate non-paged memory for secure storage"); + + // Hmmm... best to not return any allocated space in this case +#ifndef _WIN32 + free(ptr); +#else + VirtualFree((const void*) pre, MEM_RELEASE); +#endif + + return NULL; + } + + // Register the memory in the secure memory registry + SecureMemoryRegistry::i()->add(ptr, len); + + return ptr; +#else + void* ptr = (void*) malloc(len); + + if (ptr == NULL) + { + ERROR_MSG("Out of memory"); + + return NULL; + } + + // Register the memory in the secure memory registry + SecureMemoryRegistry::i()->add(ptr, len); + + return ptr; +#endif // SENSITIVE_NON_PAGED +} + +// Free memory +void sfree(void* ptr) +{ + // Unregister the memory from the secure memory registry + size_t len = SecureMemoryRegistry::i()->remove(ptr); + +#ifdef PARANOID + // First toggle all bits on + memset(ptr, 0xFF, len); +#endif // PARANOID + + // Toggle all bits off + memset(ptr, 0x00, len); + +#ifdef SENSITIVE_NON_PAGED +#ifndef _WIN32 + munlock((const void*) ptr, len); +#else + VirtualFree((const void*) pre, MEM_RELEASE); +#endif + +#endif // SENSITIVE_NON_PAGED + + free(ptr); +} + diff --git a/SoftHSMv2/src/lib/data_mgr/salloc.h b/SoftHSMv2/src/lib/data_mgr/salloc.h new file mode 100644 index 0000000..cfd92fe --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/salloc.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + salloc.h + + Contains an implementation of malloc that allocates memory securely + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SALLOC_H +#define _SOFTHSM_V2_SALLOC_H + +#include +#include "config.h" +#include "log.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Allocate memory */ +void* salloc(size_t len); + +/* Free memory */ +void sfree(void* ptr); + +#if defined (__cplusplus) +} +#endif + +#endif /* !_SOFTHSM_V2_SALLOC_H */ + diff --git a/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp new file mode 100644 index 0000000..1c635a4 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ByteStringTests.cpp + + Contains test cases to test the ByteString class + *****************************************************************************/ + +#include +#include +#include +#include +#include "ByteStringTests.h" +#include "ByteString.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(ByteStringTests); + +void ByteStringTests::setUp() +{ +} + +void ByteStringTests::tearDown() +{ + fflush(stdout); +} + +void ByteStringTests::testIntegrity() +{ + unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; + + ByteString b(testData, sizeof(testData)); + + // Test if the right data is returned + CPPUNIT_ASSERT(memcmp(testData, b.byte_str(), sizeof(testData)) == 0); + + // Test size + CPPUNIT_ASSERT(b.size() == sizeof(testData)); + + // Test the copy constructor + ByteString b2(b); + + // Test using comparison operator + CPPUNIT_ASSERT(b == b2); + + // Test using memcmp + CPPUNIT_ASSERT(memcmp(b.byte_str(), b2.byte_str(), b.size()) == 0); + + // Modify the copied version and test again + b2[1] = 0x20; + + // Test using comparison operator + CPPUNIT_ASSERT(b != b2); + + // Test using memcmp directly + CPPUNIT_ASSERT(memcmp(b.byte_str(), b2.byte_str(), b.size()) != 0); + + // Verify that b was not affected + CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0); + + // Modify the source data and check if the array operator has functioned correctly + testData[1] = 0x20; + + // Test if the right data is in b2 + CPPUNIT_ASSERT(memcmp(b2.byte_str(), testData, sizeof(testData)) == 0); +} + +void ByteStringTests::testAppend() +{ + unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; + + ByteString b; + ByteString b1(testData, sizeof(testData)); + + // Test that b is empty and b1 is not + CPPUNIT_ASSERT((b.size() == 0) && (b1.size() == sizeof(testData))); + + // Append 1 byte to b + b += 0x01; + + // Check the contents of b + CPPUNIT_ASSERT(b.size() == 1); + CPPUNIT_ASSERT(b[0] == 0x01); + + // Append another byte to b + b += 0x02; + + // Check the contents of b + CPPUNIT_ASSERT(b.size() == 2); + CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02)); + + // Append b1 to b + b += b1; + + // Check the contents of b + CPPUNIT_ASSERT(b.size() == 2 + sizeof(testData)); + CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02)); + CPPUNIT_ASSERT(memcmp(&b[2], testData, sizeof(testData)) == 0); + + // Append b to b + b += b; + + // Check the contents of b + CPPUNIT_ASSERT(b.size() == 2 * (2 + sizeof(testData))); + CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02) && + (b[(2 + sizeof(testData)) + 0] == 0x01) && + (b[(2 + sizeof(testData)) + 1] == 0x02)); + CPPUNIT_ASSERT((memcmp(&b[2], testData, sizeof(testData)) == 0) && + (memcmp(&b[2 + 2 + sizeof(testData)], testData, sizeof(testData)) == 0)); +} + +void ByteStringTests::testSubstr() +{ + unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; + + ByteString b; + ByteString b1(testData, sizeof(testData)); + + // Take a substring + b = b1.substr(8, 4); + + // Check b + CPPUNIT_ASSERT(b.size() == 4); + CPPUNIT_ASSERT(memcmp(b.byte_str(), &testData[8], 4) == 0); + + // Take another substring + b = b1.substr(8); + + // Check b + CPPUNIT_ASSERT(b.size() == 8); + CPPUNIT_ASSERT(memcmp(b.byte_str(), &testData[8], 8) == 0); + + // Two substrings added should yield the original string + b = b1.substr(0, 8) + b1.substr(8); + + // Check b + CPPUNIT_ASSERT(b.size() == sizeof(testData)); + CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0); +} + +void ByteStringTests::testFromHexStr() +{ + unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; + + ByteString b("0102030405060708090a0b0c0d0e0f10"); + ByteString b1("0102030405060708090A0B0C0D0E0F10"); + + CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0); + CPPUNIT_ASSERT(memcmp(b1.byte_str(), testData, sizeof(testData)) == 0); +} + +void ByteStringTests::testXOR() +{ + unsigned char left[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + unsigned char right[] = { 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10 }; + unsigned char xorred[] = { 0x81, 0x72, 0x63, 0x54, 0x45, 0x36, 0x27, 0x18 }; + + ByteString l(left, 8); + ByteString r(right, 8); + ByteString x(xorred, 8); + ByteString xed; + + xed = l ^ r; + + CPPUNIT_ASSERT(xed == x); + + ByteString l1(left, 8); + ByteString r1(right, 8); + + l1 ^= r1; + + CPPUNIT_ASSERT(l1 == x); + + l1 ^= l; + + CPPUNIT_ASSERT(l1 == r); + + ByteString l_(left, 7); + + xed = l_ ^ r; + + CPPUNIT_ASSERT((xed.size() == 7) && (xed == x.substr(0, 7))); + + ByteString r_(right, 7); + + xed = l ^ r_; + + CPPUNIT_ASSERT((xed.size() == 7) && (xed == x.substr(0, 7))); + + ByteString l1_(left, 8); + + l1_ ^= r_; + + CPPUNIT_ASSERT((l1.size() == 8) && (l1_.substr(0, 7) == x.substr(0,7)) && (l1_[7] == l[7])); + + ByteString l1__(left, 7); + + l1__ ^= r; + + CPPUNIT_ASSERT((l1__ == x.substr(0,7)) && (l1__.size() == 7)); +} + +void ByteStringTests::testToHexStr() +{ + ByteString b("0102030405060708090A0B0C0D0E0F"); + ByteString b1("DEADBEEF"); + ByteString b2("deadC0FFEE"); + + std::string s = b.hex_str(); + std::string s1 = b1.hex_str(); + std::string s2 = b2.hex_str(); + + CPPUNIT_ASSERT(s.compare("0102030405060708090A0B0C0D0E0F") == 0); + CPPUNIT_ASSERT(s1.compare("DEADBEEF") == 0); + CPPUNIT_ASSERT(s2.compare("DEADC0FFEE") == 0); +} + +void ByteStringTests::testLongValues() +{ + unsigned long ul1 = 0x00112233; + unsigned long ul2 = 0x10203040; + unsigned long ul3 = 0xF0E0D0C0; + + ByteString b1(ul1); + ByteString b2(ul2); + ByteString b3(ul3); + + CPPUNIT_ASSERT(b1 == ByteString("0000000000112233")); + CPPUNIT_ASSERT(b2 == ByteString("0000000010203040")); + CPPUNIT_ASSERT(b3 == ByteString("00000000F0E0D0C0")); + + CPPUNIT_ASSERT(b1.long_val() == ul1); + CPPUNIT_ASSERT(b2.long_val() == ul2); + CPPUNIT_ASSERT(b3.long_val() == ul3); + + ByteString concat = b1 + b2 + b3; + + CPPUNIT_ASSERT(concat == ByteString("0000000000112233000000001020304000000000F0E0D0C0")); + + unsigned long ulr1 = concat.firstLong(); + + CPPUNIT_ASSERT(ulr1 == ul1); + CPPUNIT_ASSERT(concat == ByteString("000000001020304000000000F0E0D0C0")); + + unsigned long ulr2 = concat.firstLong(); + + CPPUNIT_ASSERT(ulr2 == ul2); + CPPUNIT_ASSERT(concat == ByteString("00000000F0E0D0C0")); + + unsigned long ulr3 = concat.firstLong(); + + CPPUNIT_ASSERT(ulr3 == ul3); + CPPUNIT_ASSERT(concat.size() == 0); + + ByteString b4("ABCDEF"); + + CPPUNIT_ASSERT(b4.long_val() == 0xABCDEF); + CPPUNIT_ASSERT(b4.size() == 3); + CPPUNIT_ASSERT(b4.firstLong() == 0xABCDEF); + CPPUNIT_ASSERT(b4.size() == 0); +} + +void ByteStringTests::testSplitting() +{ + ByteString b("AABBCCDDEEFF112233445566"); + + ByteString b1 = b.split(6); + + CPPUNIT_ASSERT(b == ByteString("112233445566")); + CPPUNIT_ASSERT(b1 == ByteString("AABBCCDDEEFF")); + + ByteString b2 = b1.split(8); + + CPPUNIT_ASSERT(b2 == ByteString("AABBCCDDEEFF")); + CPPUNIT_ASSERT(b1.size() == 0); +} + +void ByteStringTests::testBits() +{ + ByteString b1("0"); + ByteString b2("08"); + ByteString b3("00FFFFF"); + ByteString b4("123456"); + + CPPUNIT_ASSERT(b1.bits() == 0); + CPPUNIT_ASSERT(b2.bits() == 4); + CPPUNIT_ASSERT(b3.bits() == 20); + CPPUNIT_ASSERT(b4.bits() == 21); +} + +void ByteStringTests::testSerialising() +{ + ByteString b1("AA11AA11AA11AA11AA11AA11AA11"); + ByteString b2("BB22BB22BB22BB22BB22BB22"); + ByteString b3("CC33CC33CC33CC33CC33CC33CC33CC33"); + + ByteString s1 = b1.serialise(); + + CPPUNIT_ASSERT(s1.size() == b1.size() + 8); + + ByteString d1 = ByteString::chainDeserialise(s1); + + CPPUNIT_ASSERT(s1.size() == 0); + CPPUNIT_ASSERT(d1 == b1); + + ByteString s2 = b3.serialise() + b2.serialise() + b1.serialise(); + + CPPUNIT_ASSERT(s2.size() == b1.size() + b2.size() + b3.size() + (3*8)); + + d1 = ByteString::chainDeserialise(s2); + + CPPUNIT_ASSERT(d1.size() == b3.size()); + CPPUNIT_ASSERT(s2.size() == b1.size() + b2.size() + (2*8)); + + ByteString d2 = ByteString::chainDeserialise(s2); + + CPPUNIT_ASSERT(d2.size() == b2.size()); + CPPUNIT_ASSERT(s2.size() == b1.size() + 8); + + ByteString d3 = ByteString::chainDeserialise(s2); + + CPPUNIT_ASSERT(d3.size() == b1.size()); + CPPUNIT_ASSERT(s2.size() == 0); + + CPPUNIT_ASSERT(d1 == b3); + CPPUNIT_ASSERT(d2 == b2); + CPPUNIT_ASSERT(d3 == b1); +} + diff --git a/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h new file mode 100644 index 0000000..b1dd967 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ByteStringTests.h + + Contains test cases to test the ByteString class + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_BYTESTRINGTESTS_H +#define _SOFTHSM_V2_BYTESTRINGTESTS_H + +#include + +class ByteStringTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ByteStringTests); + CPPUNIT_TEST(testIntegrity); + CPPUNIT_TEST(testAppend); + CPPUNIT_TEST(testSubstr); + CPPUNIT_TEST(testFromHexStr); + CPPUNIT_TEST(testXOR); + CPPUNIT_TEST(testToHexStr); + CPPUNIT_TEST(testLongValues); + CPPUNIT_TEST(testSplitting); + CPPUNIT_TEST(testBits); + CPPUNIT_TEST(testSerialising); + CPPUNIT_TEST_SUITE_END(); + +public: + void testIntegrity(); + void testAppend(); + void testSubstr(); + void testFromHexStr(); + void testXOR(); + void testToHexStr(); + void testLongValues(); + void testSplitting(); + void testBits(); + void testSerialising(); + + void setUp(); + void tearDown(); + +}; + +#endif // !_SOFTHSM_V2_BYTESTRINGTESTS_H + diff --git a/SoftHSMv2/src/lib/data_mgr/test/Makefile.am b/SoftHSMv2/src/lib/data_mgr/test/Makefile.am new file mode 100644 index 0000000..e1ebcdd --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/Makefile.am @@ -0,0 +1,27 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../../common \ + -I$(srcdir)/../../crypto \ + -I$(srcdir)/../../object_store \ + -I$(srcdir)/../../pkcs11 \ + -I$(srcdir)/../../session_mgr \ + -I$(srcdir)/../../slot_mgr \ + @CPPUNIT_CFLAGS@ \ + @CRYPTO_INCLUDES@ + +check_PROGRAMS = datamgrtest + +datamgrtest_SOURCES = datamgrtest.cpp \ + ByteStringTests.cpp \ + RFC4880Tests.cpp \ + SecureDataMgrTests.cpp + +datamgrtest_LDADD = ../../libsofthsm_convarch.la + +datamgrtest_LDFLAGS = @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install + +TESTS = datamgrtest + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp new file mode 100644 index 0000000..6fcfd94 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + RFC4880Tests.cpp + + Contains test cases to test the RFC4880 implementation + *****************************************************************************/ + +#include +#include +#include +#include "RFC4880Tests.h" +#include "RFC4880.h" +#include "ByteString.h" +#include "CryptoFactory.h" +#include "AESKey.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(RFC4880Tests); + +void RFC4880Tests::setUp() +{ + CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL); +} + +void RFC4880Tests::tearDown() +{ +} + +void RFC4880Tests::testRFC4880() +{ + const unsigned char* pwd1String = (const unsigned char*) "monkey"; + const unsigned char* pwd2String = (const unsigned char*) "bicycle"; + ByteString pwd1(pwd1String, strlen("monkey")); + ByteString pwd2(pwd2String, strlen("bicycle")); + + // Generate salt and make sure that two different salt values are generated and + // that the last byte is also different (resulting in a different iteration jitter + // when computing a PBE key using both salt values) + ByteString salt1, salt2; + + do + { + CPPUNIT_ASSERT(rng->generateRandom(salt1, 8) && rng->generateRandom(salt2, 8)); + } + while ((salt1 == salt2) || (salt1[salt1.size() - 1] == salt2[salt2.size() - 1])); + + // Create a password-based encryption key from the first and second password + AESKey* key1; + AESKey* key2; + + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt1, &key1)); + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt2, &key2)); + + // Check that the output keys differ and have the correct length + CPPUNIT_ASSERT(key1->getKeyBits().size() == 32); + CPPUNIT_ASSERT(key2->getKeyBits().size() == 32); + CPPUNIT_ASSERT(key1->getKeyBits() != key2->getKeyBits()); + + // Rederive the keys to check that the same output is generated every time + AESKey* key1_; + AESKey* key2_; + + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt1, &key1_)); + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt2, &key2_)); + + CPPUNIT_ASSERT(key1->getKeyBits() == key1_->getKeyBits()); + CPPUNIT_ASSERT(key2->getKeyBits() == key2_->getKeyBits()); + + // Now reverse the salts and derive new keys + AESKey* key3; + AESKey* key4; + + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt2, &key3)); + CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt1, &key4)); + + // Check that the keys are different and that they differ from the + // original keys (because different salts were used) + CPPUNIT_ASSERT(key3->getKeyBits() != key4->getKeyBits()); + CPPUNIT_ASSERT(key1->getKeyBits() != key3->getKeyBits()); + CPPUNIT_ASSERT(key1->getKeyBits() != key4->getKeyBits()); + CPPUNIT_ASSERT(key2->getKeyBits() != key3->getKeyBits()); + CPPUNIT_ASSERT(key2->getKeyBits() != key4->getKeyBits()); + + // Clean up + delete key1; + delete key2; + delete key1_; + delete key2_; + delete key3; + delete key4; +} + diff --git a/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h new file mode 100644 index 0000000..4663626 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + RFC4880Tests.h + + Contains test cases to test the RFC4880 implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_RFC4880TESTS_H +#define _SOFTHSM_V2_RFC4880TESTS_H + +#include +#include "RNG.h" + +class RFC4880Tests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RFC4880Tests); + CPPUNIT_TEST(testRFC4880); + CPPUNIT_TEST_SUITE_END(); + +public: + void testRFC4880(); + + void setUp(); + void tearDown(); + +private: + RNG* rng; +}; + +#endif // !_SOFTHSM_V2_RFC4880TESTS_H + diff --git a/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp new file mode 100644 index 0000000..7ef4816 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureDataMgrTests.cpp + + Contains test cases to test the secure data manager + *****************************************************************************/ + +#include +#include +#include +#include "SecureDataMgrTests.h" +#include "SecureDataManager.h" +#include "CryptoFactory.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(SecureDataMgrTests); + +void SecureDataMgrTests::setUp() +{ + CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL); +} + +void SecureDataMgrTests::tearDown() +{ +} + +void SecureDataMgrTests::testSecureDataManager() +{ + ByteString soPIN = "3132333435363738"; // "12345678" + ByteString userPIN = "4041424344454647"; // "ABCDEFGH" + ByteString newSOPIN = "3837363534333231"; // "87654321" + ByteString newUserPIN = "4746454443424140"; // "HGFEDCBA" + + // Instantiate a blank secure data manager + SecureDataManager s1; + ByteString plaintext = "010203040506070809"; + ByteString emptyPlaintext = ""; + ByteString encrypted; + + // Verify that no function other than setting the SO PIN works + CPPUNIT_ASSERT(!s1.setUserPIN(userPIN)); + CPPUNIT_ASSERT(!s1.loginSO(soPIN)); + CPPUNIT_ASSERT(!s1.loginUser(userPIN)); + CPPUNIT_ASSERT(!s1.reAuthenticateSO(soPIN)); + CPPUNIT_ASSERT(!s1.reAuthenticateUser(userPIN)); + CPPUNIT_ASSERT(!s1.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(!s1.decrypt(encrypted, plaintext)); + CPPUNIT_ASSERT(s1.getSOPINBlob().size() == 0); + CPPUNIT_ASSERT(s1.getUserPINBlob().size() == 0); + + // Now set the SO PIN + CPPUNIT_ASSERT(s1.setSOPIN(soPIN)); + + // Check that it is still not possible to set the user PIN + CPPUNIT_ASSERT(!s1.setUserPIN(userPIN)); + + // Check that it is possible to log in with the SO PIN + CPPUNIT_ASSERT(s1.loginSO(soPIN)); + + // Check that it is now possible to also set the user PIN + CPPUNIT_ASSERT(s1.setUserPIN(userPIN)); + + // Check that is is now also possible to log in with the user PIN + CPPUNIT_ASSERT(s1.loginUser(userPIN)); + + // Check that it is possible to encrypt and decrypt some data + ByteString decrypted; + + CPPUNIT_ASSERT(s1.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(encrypted != plaintext); + + CPPUNIT_ASSERT(s1.decrypt(encrypted, decrypted)); + CPPUNIT_ASSERT(decrypted == plaintext); + + // Log out + s1.logout(); + + // Check that it is no longer possible to set the SO PIN + CPPUNIT_ASSERT(!s1.setSOPIN(soPIN)); + + // Check that it is no longer possible to set the user PIN + CPPUNIT_ASSERT(!s1.setUserPIN(userPIN)); + + // Check that encrypting/decrypting no longer works + CPPUNIT_ASSERT(!s1.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(!s1.decrypt(encrypted, plaintext)); + + // Export the key blobs + ByteString soPINBlob = s1.getSOPINBlob(); + ByteString userPINBlob = s1.getUserPINBlob(); + + // Create a new instance with the exported key blobs + SecureDataManager s2(soPINBlob, userPINBlob); + + // Check that the key blobs match + CPPUNIT_ASSERT(s1.getSOPINBlob() == s2.getSOPINBlob()); + CPPUNIT_ASSERT(s1.getUserPINBlob() == s2.getUserPINBlob()); + + // Check that it is not possible to set the SO PIN + CPPUNIT_ASSERT(!s2.setSOPIN(soPIN)); + + // Check that it is possible to log in with the SO PIN + CPPUNIT_ASSERT(s2.loginSO(soPIN)); + + // Check that is is now also possible to log in with the user PIN + CPPUNIT_ASSERT(s2.loginUser(userPIN)); + + // Check that encrypting the data results in different ciphertext because of the random IV + ByteString encrypted2; + + CPPUNIT_ASSERT(s2.encrypt(plaintext, encrypted2)); + CPPUNIT_ASSERT(encrypted != encrypted2); + + // Check that decrypting earlier data can be done with the recreated key + CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted)); + CPPUNIT_ASSERT(decrypted == plaintext); + + // Log in with the SO PIN + CPPUNIT_ASSERT(s2.loginSO(soPIN)); + + // Check that the SO PIN can be changed + CPPUNIT_ASSERT(s2.setSOPIN(newSOPIN)); + + // Check that it is no longer possible to log in with the old SO PIN + CPPUNIT_ASSERT(!s2.loginSO(soPIN)); + + // Check that encrypting/decrypting no longer works + CPPUNIT_ASSERT(!s2.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(!s2.decrypt(encrypted, plaintext)); + + // Check that the key blobs differ + CPPUNIT_ASSERT(s1.getSOPINBlob() != s2.getSOPINBlob()); + + // Check that it is possible to log in with the new SO PIN + CPPUNIT_ASSERT(s2.loginSO(newSOPIN)); + + // Log in with the user PIN + CPPUNIT_ASSERT(s2.loginUser(userPIN)); + + // Check that it is possible to change the user PIN + CPPUNIT_ASSERT(s2.setUserPIN(newUserPIN)); + + // Check that it is no longer possible to log in with the old user PIN + CPPUNIT_ASSERT(!s2.loginUser(userPIN)); + + // Check that encrypting/decrypting no longer works + CPPUNIT_ASSERT(!s2.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(!s2.decrypt(encrypted, plaintext)); + + // Check that it is possible to log in with the new user PIN + CPPUNIT_ASSERT(s2.loginUser(newUserPIN)); + + // Check that encrypting the data results in the different ciphertext because of the random IV + CPPUNIT_ASSERT(s2.encrypt(plaintext, encrypted2)); + CPPUNIT_ASSERT(encrypted != encrypted2); + + // Check that decrypting earlier data can be done with the recreated key + CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted)); + CPPUNIT_ASSERT(decrypted == plaintext); + + // Check that empty plaintext can be handled + CPPUNIT_ASSERT(s2.encrypt(emptyPlaintext, encrypted)); + CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted)); + CPPUNIT_ASSERT(decrypted == emptyPlaintext); + + // Check that is is possible to log in with the SO PIN and re-authenticate + CPPUNIT_ASSERT(s1.loginSO(soPIN)); + CPPUNIT_ASSERT(!s1.reAuthenticateSO(userPIN)); + CPPUNIT_ASSERT(s1.reAuthenticateSO(soPIN)); + + // Check that is is possible to log in with the user PIN and re-authenticate + CPPUNIT_ASSERT(s1.loginUser(userPIN)); + CPPUNIT_ASSERT(!s1.reAuthenticateUser(soPIN)); + CPPUNIT_ASSERT(s1.reAuthenticateUser(userPIN)); + + // Check that it is possible to encrypt and decrypt some data + CPPUNIT_ASSERT(s1.encrypt(plaintext, encrypted)); + CPPUNIT_ASSERT(encrypted != plaintext); + + CPPUNIT_ASSERT(s1.decrypt(encrypted, decrypted)); + CPPUNIT_ASSERT(decrypted == plaintext); +} + diff --git a/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h new file mode 100644 index 0000000..743a01b --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SecureDataMgrTests.h + + Contains test cases to test the secure data manager + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SECUREDATAMGRTESTS_H +#define _SOFTHSM_V2_SECUREDATAMGRTESTS_H + +#include +#include "RNG.h" + +class SecureDataMgrTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SecureDataMgrTests); + CPPUNIT_TEST(testSecureDataManager); + CPPUNIT_TEST_SUITE_END(); + +public: + void testSecureDataManager(); + + void setUp(); + void tearDown(); + +private: + RNG* rng; +}; + +#endif // !_SOFTHSM_V2_SECUREDATAMGRTESTS_H + diff --git a/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp b/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp new file mode 100644 index 0000000..49fa535 --- /dev/null +++ b/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + datamgrtest.cpp + + The main test executor for tests on the secure data manager in SoftHSM v2 + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#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::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr BotanCryptoFactory::instance(NULL); +#endif + +#endif + +int main(int /*argc*/, char** /*argv*/) +{ + CppUnit::TestResult controller; + CppUnit::TestResultCollector result; + CppUnit::TextUi::TestRunner runner; + controller.addListener(&result); + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/SoftHSMv2/src/lib/handle_mgr/Handle.cpp b/SoftHSMv2/src/lib/handle_mgr/Handle.cpp new file mode 100644 index 0000000..127b4c7 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/Handle.cpp @@ -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 index 0000000..94b42f9 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/Handle.h @@ -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 index 0000000..ccf42d0 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/HandleManager.cpp @@ -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 index 0000000..e85e628 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/HandleManager.h @@ -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 + +#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 index 0000000..108f74d --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/Makefile.am @@ -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 index 0000000..fbf0403 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.cpp @@ -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 +#include +#include +#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 index 0000000..02022e4 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/test/HandleManagerTests.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + HandleManagerTests.h + + Contains test cases to test the handle manager implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_HANDLEMANAGERTESTS_H +#define _SOFTHSM_V2_HANDLEMANAGERTESTS_H + +#include +#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 index 0000000..8d110b0 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/test/Makefile.am @@ -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 index 0000000..eedb407 --- /dev/null +++ b/SoftHSMv2/src/lib/handle_mgr/test/handlemgrtest.cpp @@ -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 +#include +#include +#include +#include +#include + +#include "config.h" +#include "MutexFactory.h" + +#ifdef HAVE_CXX11 +std::unique_ptr MutexFactory::instance(nullptr); +#else +std::auto_ptr 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 ®istry = 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 index 0000000..2dfd0eb --- /dev/null +++ b/SoftHSMv2/src/lib/main.cpp @@ -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 index 0000000..d82d7cb --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DB.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DB.h" + +#if HAVE_SQL_TRACE +static void xTrace(void*connectionLabel,const char*zSql) +{ + const char *label = static_cast(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 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(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 index 0000000..e4e1a11 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DB.h @@ -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 +#include + +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 index 0000000..d2515bd --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DBObject.cpp @@ -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 +#include +#include + +#include +#include + +// 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::iterator it = _attributes.begin(); it!=_attributes.end(); ++it) { + delete it->second; + it->second = NULL; + } + if (_transaction) + { + for (std::map::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& 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& set) +{ + for (std::set::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& 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 (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 (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 (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 value; + if (!decodeMechanismTypeSet(value, binary + pos, len)) { + return false; + } + pos += len; + + map.insert(std::pair (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& attributes) +{ + for (std::map::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 *attrs = &_attributes; + if (_transaction) + attrs = _transaction; + + bool value = result.getInt(1) != 0; + std::map::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 *attrs = &_attributes; + if (_transaction) + attrs = _transaction; + + unsigned long value = result.getULongLong(1); + std::map::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 *attrs = &_attributes; + if (_transaction) + attrs = _transaction; + + const unsigned char *value = result.getBinary(1); + size_t size = result.getFieldLength(1); + std::map::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 *attrs = &_attributes; + if (_transaction) + attrs = _transaction; + + const unsigned char *value = result.getBinary(1); + size_t size = result.getFieldLength(1); + + std::set set; + if (!decodeMechanismTypeSet(set, value, size)) + { + return NULL; + } + + OSAttribute *attr; + std::map::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 *attrs = &_attributes; + if (_transaction) + attrs = _transaction; + + const unsigned char *binary = result.getBinary(1); + size_t size = result.getFieldLength(1); + std::map::iterator it = attrs->find(type); + OSAttribute *attr; + if (it != attrs->end()) + { + std::map 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 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::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::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(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::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(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::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; + 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::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) { + std::map::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::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 index 0000000..4dc1249 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DBObject.h @@ -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 + +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 _attributes; + std::map *_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 index 0000000..e734372 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DBToken.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 cleanUp = _allObjects; + _allObjects.clear(); + for (std::map::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 DBToken::getObjects() +{ + std::set objects; + getObjects(objects); + return objects; +} + +void DBToken::getObjects(std::set &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::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(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 tokenFiles = dir.getFiles(); + + for (std::vector::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 cleanUp = getObjects(); + + for (std::set::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 index 0000000..ef4c28e --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DBToken.h @@ -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 +#include + +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 getObjects(); + + // Insert objects into the given set + virtual void getObjects(std::set &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 _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 index 0000000..e964d32 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/Directory.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + Directory.cpp + + Helper functions for accessing directories. + *****************************************************************************/ + +#include "config.h" +#include "Directory.h" +#include "OSPathSep.h" +#include "log.h" +#include +#include +#ifndef _WIN32 +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include + +// 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 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 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 index 0000000..d7681a1 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/Directory.h @@ -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 +#include + +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 getFiles(); + + // Return a list of all subdirectories in a directory + std::vector 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 files; + + // All subdirectories in the directory + std::vector 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 index 0000000..2af8ea9 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/File.cpp @@ -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 +#include +#include +#ifndef _WIN32 +#include +#include +#else +#include +#define F_SETLK 12 +#define F_SETLKW 13 +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 +#endif +#include +#include +#include + +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& 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& 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 (attrType, val)); + } + break; + + case akInteger: + { + unsigned long val; + if (!readULong(val)) + { + return false; + } + if (8 > len) + { + return false; + } + len -= 8; + + value.insert(std::pair (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 (attrType, val)); + } + break; + + case akMechSet: + { + std::set val; + if (!readMechanismTypeSet(val)) + { + return false; + } + if (8 + val.size() * 8 > len) + { + return false; + } + len -= 8 + val.size() * 8; + + value.insert(std::pair (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& value) +{ + if (!valid) return false; + + // write length + if (!writeULong(value.size())) + { + return false; + } + + // write each value + for (std::set::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& value) +{ + if (!valid) return false; + + // compute length + unsigned long len = 0; + for (std::map::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 val = attr.getMechanismTypeSetValue(); + len += 8 + val.size() * 8; + } + else + { + return false; + } + } + + // write length + if (!writeULong(len)) + { + return false; + } + + // write each attribute + for (std::map::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 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 index 0000000..da27af6 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/File.h @@ -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 +#include + +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& value); + + // Read an array value; warning: not thread safe without locking! + bool readAttributeMap(std::map& 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& value); + + // Write an attribute map value; warning: not thread safe without locking! + bool writeAttributeMap(const std::map& 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 index 0000000..db6dda1 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/FindOperation.cpp @@ -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 &handles) +{ + _handles = handles; +} + +CK_ULONG FindOperation::retrieveHandles(CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulCount) +{ + CK_ULONG ulReturn = 0; + std::set::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::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 index 0000000..ea6410a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/FindOperation.h @@ -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 +#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 &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 _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 index 0000000..196dac2 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/Generation.cpp @@ -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 index 0000000..106f34b --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/Generation.h @@ -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 +#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 index 0000000..d3e89d3 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/Makefile.am @@ -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 index 0000000..9d7e5a3 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSAttribute.cpp @@ -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& value) +{ + mechSetValue = value; + attributeType = MECHSET; + + boolValue = false; + ulongValue = 0; +} + +// Constructor for an attribute map type attribute +OSAttribute::OSAttribute(const std::map& 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& OSAttribute::getMechanismTypeSetValue() const +{ + return mechSetValue; +} + +const std::map& 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::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 index 0000000..303a5b9 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSAttribute.h @@ -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 +#include + +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& value); + + // Constructor for an attribute map type attribute + OSAttribute(const std::map& 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& getMechanismTypeSetValue() const; + const std::map& 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 mechSetValue; + std::map 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 index 0000000..dfc5869 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSAttributes.h @@ -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 index 0000000..6efaa6d --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSObject.h @@ -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 index 0000000..f714d24 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSPathSep.h @@ -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 index 0000000..13b1eaa --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSToken.cpp @@ -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 +#include +#include +#include +#include +#include + +// 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 cleanUp = allObjects; + allObjects.clear(); + + for (std::set::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 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 &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(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 tokenFiles = tokenDir->getFiles(); + + for (std::vector::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 cleanUp = getObjects(); + + MutexLocker lock(tokenMutex); + + for (std::set::iterator i = cleanUp.begin(); i != cleanUp.end(); i++) + { + ObjectFile* fileObject = dynamic_cast(*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 tokenFiles = tokenDir->getFiles(); + + // Filter out the objects + std::set newSet; + + for (std::vector::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 addedFiles; + std::set removedFiles; + + if (!isFirstTime) + { + // First compute which files were added + for (std::set::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::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::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 newObjects; + + for (std::set::iterator i = objects.begin(); i != objects.end(); i++) + { + ObjectFile* fileObject = dynamic_cast((*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 index 0000000..4ba5b2c --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/OSToken.h @@ -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 +#include +#include +#include + +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 getObjects(); + + // Insert objects into the given set + virtual void getObjects(std::set &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 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 allObjects; + + // The current list of files + std::set 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 index 0000000..f3becbe --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectFile.cpp @@ -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 +#endif +#include +#include +#include + +// 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::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 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 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::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& 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& 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 cleanUp = attributes; + attributes.clear(); + + for (std::map::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 index 0000000..a13d835 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectFile.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 +#include +#include +#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 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 index 0000000..3855d9d --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectStore.cpp @@ -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 + +// 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 dirs = storeDir.getSubDirs(); + + for (std::vector::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::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::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 index 0000000..e8ecd1a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectStore.h @@ -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 +#include + +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 tokens; + + // All tokens + std::vector 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 index 0000000..24c2049 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectStoreToken.cpp @@ -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(OSToken::createToken); +static AccessToken static_accessToken = reinterpret_cast(OSToken::accessToken); + +// Create a new token +/*static*/ bool ObjectStoreToken::selectBackend(const std::string &backend) +{ + if (backend == "file") + { + static_createToken = reinterpret_cast(OSToken::createToken); + static_accessToken = reinterpret_cast(OSToken::accessToken); + } +#ifdef HAVE_OBJECTSTORE_BACKEND_DB + else if (backend == "db") + { + static_createToken = reinterpret_cast(DBToken::createToken); + static_accessToken = reinterpret_cast(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 index 0000000..668dccc --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/ObjectStoreToken.h @@ -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 +#include + +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 getObjects() = 0; + + // Insert objects into the given set + virtual void getObjects(std::set &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 index 0000000..49dfa7d --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/SessionObject.cpp @@ -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::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 cleanUp = attributes; + attributes.clear(); + + for (std::map::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 index 0000000..caadb64 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/SessionObject.h @@ -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 +#include +#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 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 index 0000000..3370d20 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/SessionObjectStore.cpp @@ -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 +#include +#include +#include +#include + +// Constructor +SessionObjectStore::SessionObjectStore() +{ + storeMutex = MutexFactory::i()->getMutex(); +} + +// Destructor +SessionObjectStore::~SessionObjectStore() +{ + // Clean up + objects.clear(); + std::set cleanUp = allObjects; + allObjects.clear(); + + for (std::set::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 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 &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::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 checkObjects = objects; + + for (std::set::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 checkObjects = objects; + + for (std::set::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 checkObjects = objects; + + for (std::set::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 clearObjects = allObjects; + allObjects.clear(); + + for (std::set::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 index 0000000..2ec4bc5 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/SessionObjectStore.h @@ -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 +#include +#include +#include +#include + +class SessionObjectStore +{ +public: + // Constructor + SessionObjectStore(); + + // Retrieve objects + std::set getObjects(); + + // Insert the session objects for the given slotID into the given OSObject set + void getObjects(CK_SLOT_ID slotID, std::set &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 objects; + + // All the objects ever kept in the store + std::set allObjects; + + // The current list of files + std::set 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 index 0000000..9e9f541 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/UUID.cpp @@ -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 +#include +#include +#include + +// 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 index 0000000..569bc00 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/UUID.h @@ -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 + +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 index 0000000..2cc8360 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectStoreTests.cpp + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#include +#include +#include +#include "DBObjectStoreTests.h" + +#include + +#ifndef HAVE_SQLITE3_H +#error expected sqlite3 to be available +#endif + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store); + +void test_a_newly_created_object_store::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + + ObjectStoreToken::selectBackend("db"); + + store = new ObjectStore("testdir"); + nulltoken = NULL; +} + +void test_a_newly_created_object_store::tearDown() +{ + delete store; + + ObjectStoreToken::selectBackend("file"); + +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + + +void test_a_newly_created_object_store::contains_no_items() +{ + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)0); +} + +void test_a_newly_created_object_store::can_create_a_new_token() +{ + ByteString label1 = "DEADC0FFEE"; + + ObjectStoreToken *token1 = store->newToken(label1); + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store_containing_two_tokens); + + +void test_a_newly_created_object_store_containing_two_tokens::setUp() +{ + test_a_newly_created_object_store::setUp(); + + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + ObjectStoreToken* token1 = store->newToken(label1); + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1); + + ObjectStoreToken* token2 = store->newToken(label2); + CPPUNIT_ASSERT(token2 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2); +} + +void test_a_newly_created_object_store_containing_two_tokens::tearDown() +{ + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + CPPUNIT_ASSERT(store->destroyToken(token1)); + CPPUNIT_ASSERT(store->destroyToken(token2)); + + test_a_newly_created_object_store::tearDown(); +} + +void test_a_newly_created_object_store_containing_two_tokens::has_two_tokens() +{ + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2); +} + +void test_a_newly_created_object_store_containing_two_tokens::can_access_both_tokens() +{ + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT(token2 != nulltoken); +} + +void test_a_newly_created_object_store_containing_two_tokens::assigned_labels_correctly_to_tokens() +{ + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + ByteString retrieveLabel1, retrieveLabel2; + + CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2)); + + CPPUNIT_ASSERT(label1 == retrieveLabel1 || label1 == retrieveLabel2); + CPPUNIT_ASSERT(label2 == retrieveLabel1 || label2 == retrieveLabel2); + CPPUNIT_ASSERT(label1 != label2); +} + +void test_a_newly_created_object_store_containing_two_tokens::assigned_a_unique_serial_number_to_each_token() +{ + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + ByteString retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h new file mode 100644 index 0000000..7d100c8 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectStoreTests.h + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBOBJECTSTORETESTS_H +#define _SOFTHSM_V2_DBOBJECTSTORETESTS_H + +#include +#include "ObjectStore.h" +#include "ObjectStoreToken.h" + +class test_a_newly_created_object_store : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_newly_created_object_store); + CPPUNIT_TEST(contains_no_items); + CPPUNIT_TEST(can_create_a_new_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void contains_no_items(); + void can_create_a_new_token(); +protected: + ObjectStore *store; + ObjectStoreToken *nulltoken; + +private: +}; + +class test_a_newly_created_object_store_containing_two_tokens : public test_a_newly_created_object_store +{ + CPPUNIT_TEST_SUITE(test_a_newly_created_object_store_containing_two_tokens); + CPPUNIT_TEST(has_two_tokens); + CPPUNIT_TEST(can_access_both_tokens); + CPPUNIT_TEST(assigned_labels_correctly_to_tokens); + CPPUNIT_TEST(assigned_a_unique_serial_number_to_each_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void has_two_tokens(); + void can_access_both_tokens(); + void assigned_labels_correctly_to_tokens(); + void assigned_a_unique_serial_number_to_each_token(); +}; + +#endif // !_SOFTHSM_V2_DBOBJECTSTORETESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp new file mode 100644 index 0000000..d856b06 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectTests.cpp + + Contains test cases to test the database token object implementation + *****************************************************************************/ + +#include +#include +#include +#include "DBObjectTests.h" +#include "DBObject.h" + +#include + +#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 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 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 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 mattr; + mattr.insert(std::pair (CKA_TOKEN, attr1)); + mattr.insert(std::pair (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair (CKA_VALUE, attr3)); + mattr.insert(std::pair (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 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 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 value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set 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 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 value5a; + value5a.insert(CKM_SHA384); + value5a.insert(CKM_SHA512); + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + OSAttribute attr4a(value4a); + OSAttribute attr5a(value5a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5a)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5); + + // Commit the transaction + CPPUNIT_ASSERT(testObject.commitTransaction()); + + // Verify that non-modifiable attributes did not propagate but modifiable attributes + // have now changed on the other instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // NOTE: 3 attributes below cannot be modified after creation and therefore are not required to propagate. + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() != value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() != value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() != value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() != value5a); + + // CKA_ID attribute can be modified after creation and therefore should have propagated. + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5); + + // Create a fresh third instance for the same object to force the data to be retrieved from the database. + DBObject testObject3(connection2); + CPPUNIT_ASSERT(testObject3.find(1)); + CPPUNIT_ASSERT(testObject3.isValid()); + + // Verify that they are unchanged on the other instance, while the transaction is still in progress. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // Verify that the attributes from the database are still hodling the same value as when the transaction started. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Abort the transaction + CPPUNIT_ASSERT(testObject.abortTransaction()); + + // Verify that after aborting the transaction the values in testObject have reverted back to their + // original state. + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // After aborting a transaction the testObject should be back to pre transaction state. + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Verify that testObject3 still has the original values. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // Verify that testObject3 still has the original values. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); +} + +void test_a_dbobject_with_an_object::should_fail_to_delete() +{ + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + // We don't attach the object to a token, and therefore should not be able to destroy it. + CPPUNIT_ASSERT(!testObject.destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h new file mode 100644 index 0000000..136fa81 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectTests.h + + Contains test cases to test the database token object implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBOBJECTTESTS_H +#define _SOFTHSM_V2_DBOBJECTTESTS_H + +#include +#include "DB.h" + +class test_a_dbobject : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_dbobject); + CPPUNIT_TEST(should_be_insertable); + CPPUNIT_TEST(should_be_selectable); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_be_insertable(); + void should_be_selectable(); + +protected: + DB::Connection *connection; + DB::Connection *connection2; + +private: +}; + +class test_a_dbobject_with_an_object : public test_a_dbobject +{ + CPPUNIT_TEST_SUITE(test_a_dbobject_with_an_object); + CPPUNIT_TEST(should_store_boolean_attributes); + CPPUNIT_TEST(should_store_unsigned_long_attributes); + CPPUNIT_TEST(should_store_binary_attributes); + CPPUNIT_TEST(should_store_mechtypeset_attributes); + CPPUNIT_TEST(should_store_attrmap_attributes); + CPPUNIT_TEST(should_store_mixed_attributes); + CPPUNIT_TEST(should_store_double_attributes); + CPPUNIT_TEST(can_refresh_attributes); + CPPUNIT_TEST(should_cleanup_statements_during_transactions); + CPPUNIT_TEST(should_use_transactions); + CPPUNIT_TEST(should_fail_to_delete); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_store_boolean_attributes(); + void should_store_unsigned_long_attributes(); + void should_store_binary_attributes(); + void should_store_mechtypeset_attributes(); + void should_store_attrmap_attributes(); + void should_store_mixed_attributes(); + void should_store_double_attributes(); + void can_refresh_attributes(); + void should_cleanup_statements_during_transactions(); + void should_use_transactions(); + void should_fail_to_delete(); +}; + +#endif // !_SOFTHSM_V2_DBOBJECTTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp new file mode 100644 index 0000000..d787a83 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTests.cpp + + Contains lowest level test cases for the database backend implementation. + *****************************************************************************/ + +#include +#include +#include +#include "DBTests.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db); + +static int dummy_print(const char *, va_list ) +{ + return 0; +} + +void test_a_db::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + null = NULL; +} + +void test_a_db::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void test_a_db::checks_for_empty_connection_parameters() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection = DB::Connection::Create("","TestToken"); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("testdir",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + DB::setLogErrorHandler(eh); +} + +void test_a_db::can_be_connected_to_database() +{ + + DB::Connection *connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + bool isConnected = connection->connect(); + delete connection; + CPPUNIT_ASSERT(isConnected); +#ifndef _WIN32 + CPPUNIT_ASSERT_EQUAL(system("test -f ./testdir/TestToken"), 0); +#else + CPPUNIT_ASSERT(GetFileAttributes("testdir\\TestToken") != INVALID_FILE_ATTRIBUTES); +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection); + +void test_a_db_with_a_connection::setUp() +{ + test_a_db::setUp(); + connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + CPPUNIT_ASSERT(connection->connect()); +} + +void test_a_db_with_a_connection::tearDown() +{ + CPPUNIT_ASSERT(connection != null); + connection->close(); + delete connection; + test_a_db::tearDown(); +} + +void test_a_db_with_a_connection::can_prepare_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); +} + +void test_a_db_with_a_connection::can_perform_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + // only expect a single row in the result, so nextRow should now fail + CPPUNIT_ASSERT(!result.nextRow()); +} + +void test_a_db_with_a_connection::maintains_correct_refcounts() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + { + DB::Statement statement1 = statement; + DB::Statement statement2 = statement; + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 3); + CPPUNIT_ASSERT(statement1.isValid()); + CPPUNIT_ASSERT(statement2.isValid()); + } + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // Statement is referenced by the result because it provides the query record cursor state. + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 2); + + result = DB::Result(); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); +} +void test_a_db_with_a_connection::can_create_tables() +{ + CPPUNIT_ASSERT(!connection->tableExists("object")); + DB::Statement cr_object = connection->prepare("create table object (id integer primary key autoincrement);"); + CPPUNIT_ASSERT(connection->execute(cr_object)); + CPPUNIT_ASSERT(connection->tableExists("object")); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables); + +void test_a_db_with_a_connection_with_tables::setUp() +{ + test_a_db_with_a_connection::setUp(); + can_create_tables(); + + // attribute_text + CPPUNIT_ASSERT(!connection->tableExists("attribute_text")); + DB::Statement cr_attr_text = connection->prepare( + "create table attribute_text (" + "value text," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_text)); + CPPUNIT_ASSERT(connection->tableExists("attribute_text")); + + // attribute_integer + CPPUNIT_ASSERT(!connection->tableExists("attribute_integer")); + DB::Statement cr_attr_integer = connection->prepare( + "create table attribute_integer (" + "value integer," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_integer)); + CPPUNIT_ASSERT(connection->tableExists("attribute_integer")); + + // attribute_blob + CPPUNIT_ASSERT(!connection->tableExists("attribute_blob")); + DB::Statement cr_attr_blob = connection->prepare( + "create table attribute_blob (" + "value blob," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_blob)); + CPPUNIT_ASSERT(connection->tableExists("attribute_blob")); + + // attribute_boolean + CPPUNIT_ASSERT(!connection->tableExists("attribute_boolean")); + DB::Statement cr_attr_boolean = connection->prepare( + "create table attribute_boolean (" + "value boolean," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_boolean)); + CPPUNIT_ASSERT(connection->tableExists("attribute_boolean")); + + // attribute_datetime + CPPUNIT_ASSERT(!connection->tableExists("attribute_datetime")); + DB::Statement cr_attr_datetime = connection->prepare( + "create table attribute_datetime (" + "value datetime," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_datetime)); + CPPUNIT_ASSERT(connection->tableExists("attribute_datetime")); + + // attribute_real + CPPUNIT_ASSERT(!connection->tableExists("attribute_real")); + DB::Statement cr_attr_real = connection->prepare( + "create table attribute_real (" + "value real," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_real)); + CPPUNIT_ASSERT(connection->tableExists("attribute_real")); +} + +void test_a_db_with_a_connection_with_tables::tearDown() +{ + test_a_db_with_a_connection::tearDown(); +} + +void test_a_db_with_a_connection_with_tables::can_insert_records() +{ + DB::Statement statement = connection->prepare("insert into object default values"); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + statement = connection->prepare( + "insert into attribute_text (value,type,object_id) values ('%s',%d,%lld)", + "testing testing testing", + 1234, + object_id); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_retrieve_records() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare( + "select value from attribute_text as t where t.type=%d", + 1234); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), std::string("testing testing testing")); +} + +void test_a_db_with_a_connection_with_tables::can_cascade_delete_objects_and_attributes() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare("select id from object"); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); + + statement = connection->prepare("delete from object where id=%lld",object_id); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare("select * from attribute_text where object_id=%lld",object_id); + result = connection->perform(statement); + + // Check cascade delete was successful. + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value='test test test' where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute_bound_value() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value=? where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + std::string msg("testing quote ' and accents é."); + + CPPUNIT_ASSERT(DB::Bindings(statement).bindText(1,msg.c_str(),msg.size(),NULL)); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare( + "select value from attribute_text as t where t.type=%d and t.object_id=%lld", + 1234, + object_id); + result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), msg); +} + +void test_a_db_with_a_connection_with_tables::can_update_integer_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert integer attribute + statement = connection->prepare( + "insert into attribute_integer (value,type,object_id) values (%lld,%d,%lld)", + 1111, + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update integer attribute statement + statement = connection->prepare( + "update attribute_integer set value=? where type=%d and object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind long long value to the parameter an update the record + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt64(1,2222)); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the value from the record + DB::Statement retrieveStmt = connection->prepare( + "select value from attribute_integer as t where t.type=%d and t.object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(retrieveStmt.isValid()); + DB::Result result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)2222); + + // verify that binding to a parameter before resetting the statement will fail. + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + DB::Bindings bindings(statement); + CPPUNIT_ASSERT(!bindings.bindInt(1,3333)); + DB::setLogErrorHandler(eh); + + // reset statement and bind another value to the statement + CPPUNIT_ASSERT(bindings.reset()); + CPPUNIT_ASSERT(bindings.bindInt(1,3333)); + + // perform the update statement again with the newly bound value + CPPUNIT_ASSERT(connection->execute(statement)); + + // reset the retrieve statement and perform it again to get the latest value of the integer attribute + CPPUNIT_ASSERT(retrieveStmt.reset()); + result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT(result.isValid()); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)3333); +} + +void test_a_db_with_a_connection_with_tables::can_update_blob_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert blob attribute + statement = connection->prepare( + "insert into attribute_blob (value,type,object_id) values (X'012345',%d,%lld)", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update blob attribute statement + statement = connection->prepare( + "update attribute_blob set value=? where type=%d and object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind blob (with embedded zero!) to the parameter + const char data[] = {10,11,0,12,13,14,15,16}; + std::string msg(data,sizeof(data)); + CPPUNIT_ASSERT(DB::Bindings(statement).bindBlob(1,msg.data(),msg.size(),NULL)); + + // update the blob value of the attribute + CPPUNIT_ASSERT(connection->execute(statement)); + + // retrieve the blob value from the attribute + statement = connection->prepare( + "select value from attribute_blob as t where t.type=%d and t.object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved blob value matches the original data. + CPPUNIT_ASSERT_EQUAL(result.getFieldLength(1), sizeof(data)); + std::string msgstored((const char *)result.getBinary(1),result.getFieldLength(1)); + CPPUNIT_ASSERT_EQUAL(msg, msgstored); +} + + +void test_a_db_with_a_connection_with_tables::will_not_insert_non_existing_attribute_on_update() +{ + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // Updating an attribute before it is created will succeed, but will not insert an attribute. + statement = connection->prepare( + "update attribute_boolean set value=1 where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute should fail + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_boolean_attribute_bound_value() +{ + //SQLite doesn't have a boolean data type, use 0 (false) and 1 (true) + + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert boolean attribute + statement = connection->prepare( + "insert into attribute_boolean (value,type,object_id) values (1,%d,%lld)", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update boolean attribute statement + statement = connection->prepare( + "update attribute_boolean set value=? where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 0 (false) to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt(1,0)); + + // Execute the statement to update the attribute value. + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value + CPPUNIT_ASSERT_EQUAL(result.getInt(1), 0); +} + + +void test_a_db_with_a_connection_with_tables::can_update_real_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert real value + statement = connection->prepare( + "insert into attribute_real (value,type,object_id) values(%f,%d,%lld)", + 1.238, + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update real attribute statement + statement = connection->prepare( + "update attribute_real set value=? where type=%d and object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 3333.3333 to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindDouble(1,3333.3333)); + + // Execute the statement to update the attribute value + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the double value from the attribute + statement = connection->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); +} + +void test_a_db_with_a_connection_with_tables::supports_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->rollbackTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + CPPUNIT_ASSERT(connection->rollbackTransaction()); + + eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->commitTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + can_update_real_attribute_bound_value(); + CPPUNIT_ASSERT(connection->commitTransaction()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables_with_a_second_connection_open); + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::setUp() +{ + test_a_db_with_a_connection_with_tables::setUp(); + connection2 = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection2 != null); + CPPUNIT_ASSERT(connection2->connect()); + connection2->setBusyTimeout(10); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::tearDown() +{ + CPPUNIT_ASSERT(connection2 != null); + connection2->close(); + delete connection2; + test_a_db_with_a_connection_with_tables::tearDown(); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::handles_nested_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection1 = connection; + + CPPUNIT_ASSERT(connection1->beginTransactionRW()); + + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + CPPUNIT_ASSERT(connection2->rollbackTransaction()); + CPPUNIT_ASSERT(!connection2->beginTransactionRW()); + + CPPUNIT_ASSERT(connection1->commitTransaction()); + + DB::setLogErrorHandler(eh); +} + + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::supports_transactions_with_other_connections_open() +{ + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + + supports_transactions(); + + // Retrieve the double value from the attribute + DB::Statement statement = connection2->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + connection->lastInsertRowId()); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection2->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); + + CPPUNIT_ASSERT(connection2->commitTransaction()); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.h b/SoftHSMv2/src/lib/object_store/test/DBTests.h new file mode 100644 index 0000000..422cbce --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTests.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTests.h + + Contains lowest level test cases for the database backend implementation. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBTESTS_H +#define _SOFTHSM_V2_DBTESTS_H + +#include +#include "DB.h" + +class test_a_db : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_db); + CPPUNIT_TEST(checks_for_empty_connection_parameters); + CPPUNIT_TEST(can_be_connected_to_database); + CPPUNIT_TEST_SUITE_END(); + +public: + void checks_for_empty_connection_parameters(); + void can_be_connected_to_database(); + + void setUp(); + void tearDown(); + +protected: + DB::Connection *null; + +private: +}; + +class test_a_db_with_a_connection : public test_a_db +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection); + CPPUNIT_TEST(can_prepare_statements); + CPPUNIT_TEST(can_perform_statements); + CPPUNIT_TEST(maintains_correct_refcounts); + CPPUNIT_TEST(can_create_tables); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void can_prepare_statements(); + void can_perform_statements(); + void maintains_correct_refcounts(); + void can_create_tables(); +protected: + DB::Connection *connection; + +private: +}; + +class test_a_db_with_a_connection_with_tables : public test_a_db_with_a_connection +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables); + CPPUNIT_TEST(can_insert_records); + CPPUNIT_TEST(can_retrieve_records); + CPPUNIT_TEST(can_cascade_delete_objects_and_attributes); + CPPUNIT_TEST(can_update_text_attribute); + CPPUNIT_TEST(can_update_text_attribute_bound_value); + CPPUNIT_TEST(can_update_integer_attribute_bound_value); + CPPUNIT_TEST(can_update_blob_attribute_bound_value); + CPPUNIT_TEST(will_not_insert_non_existing_attribute_on_update); + CPPUNIT_TEST(can_update_boolean_attribute_bound_value); + CPPUNIT_TEST(can_update_real_attribute_bound_value); + CPPUNIT_TEST(supports_transactions); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void can_insert_records(); + void can_retrieve_records(); + void can_cascade_delete_objects_and_attributes(); + void can_update_text_attribute(); + void can_update_text_attribute_bound_value(); + void can_update_integer_attribute_bound_value(); + void can_update_blob_attribute_bound_value(); + void will_not_insert_non_existing_attribute_on_update(); + void can_update_boolean_attribute_bound_value(); + void can_update_real_attribute_bound_value(); + void supports_transactions(); +protected: + +private: +}; + +class test_a_db_with_a_connection_with_tables_with_a_second_connection_open : public test_a_db_with_a_connection_with_tables +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables_with_a_second_connection_open); + CPPUNIT_TEST(handles_nested_transactions); + CPPUNIT_TEST(supports_transactions_with_other_connections_open); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void handles_nested_transactions(); + void supports_transactions_with_other_connections_open(); +protected: + DB::Connection *connection2; + +private: +}; + +#endif // !_SOFTHSM_V2_DBTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp new file mode 100644 index 0000000..ab0cff1 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTokenTests.cpp + + Contains test cases to test the database token implementation + *****************************************************************************/ +#include +#include +#include +#include "DBTokenTests.h" +#include "DBToken.h" +#include "DB.h" + +#include + +#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 objects = existingToken.getObjects(); + + for (std::set::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 objects = testToken->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set::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 otherObjects = sameToken.getObjects(); + CPPUNIT_ASSERT_EQUAL(otherObjects.size(), (size_t)3); + + bool present2[3] = { false, false, false }; + + for (std::set::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::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::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::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 objects = referencingToken.getObjects(); + CPPUNIT_ASSERT_EQUAL(objects.size(), (size_t)0); + + CPPUNIT_ASSERT(!referencingToken.isValid()); +#endif + + DB::setLogErrorHandler(eh); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h new file mode 100644 index 0000000..de25195 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTokenTests.h + + Contains test cases to test the database token implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBTOKENTESTS_H +#define _SOFTHSM_V2_DBTOKENTESTS_H + +#include +#include "DBToken.h" + +class test_a_dbtoken : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_dbtoken); + CPPUNIT_TEST(should_be_creatable); + CPPUNIT_TEST(should_support_pin_setting_getting); + CPPUNIT_TEST(should_allow_object_enumeration); + CPPUNIT_TEST(should_fail_to_open_nonexistant_tokens); + CPPUNIT_TEST(support_create_delete_objects); + CPPUNIT_TEST(support_clearing_a_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_be_creatable(); + void should_support_pin_setting_getting(); + void should_allow_object_enumeration(); + void should_fail_to_open_nonexistant_tokens(); + void support_create_delete_objects(); + void support_clearing_a_token(); + +protected: + +private: +}; + +#endif // !_SOFTHSM_V2_DBTOKENTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp new file mode 100644 index 0000000..2b56a5a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DirectoryTests.cpp + + Contains test cases to test the directory implementation + *****************************************************************************/ + +#include +#include +#include +#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 files = testdir.getFiles(); + std::vector 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::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::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::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::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::iterator i = files.begin(); i != files.end(); i++) + { + if (!i->compare("afile")) + { + fileSeen2[0] = true; + } + else if (!i->compare("justaFile")) + { + fileSeen2[1] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(fileSeen2[0] && fileSeen2[1]); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h new file mode 100644 index 0000000..777f1a8 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DirectoryTests.h + + Contains test cases to test the Directory implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DIRECTORYTESTS_H +#define _SOFTHSM_V2_DIRECTORYTESTS_H + +#include + +class DirectoryTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(DirectoryTests); + CPPUNIT_TEST(testDirectory); + CPPUNIT_TEST_SUITE_END(); + +public: + void testDirectory(); + + void setUp(); + void tearDown(); + +private: +}; + +#endif // !_SOFTHSM_V2_DIRECTORYTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.cpp b/SoftHSMv2/src/lib/object_store/test/FileTests.cpp new file mode 100644 index 0000000..9ac0979 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/FileTests.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + FileTests.cpp + + Contains test cases to test the file implementation + *****************************************************************************/ + +#include +#include +#include +#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 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 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 files = dir.getFiles(); + + for (std::vector::iterator i = files.begin(); i != files.end(); i++) + { + if (!i->compare(name)) + { + return true; + } + } + + return false; +} + diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.h b/SoftHSMv2/src/lib/object_store/test/FileTests.h new file mode 100644 index 0000000..0b87f26 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/FileTests.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + FileTests.h + + Contains test cases to test the File implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_FILETESTS_H +#define _SOFTHSM_V2_FILETESTS_H + +#include + +class FileTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(FileTests); + CPPUNIT_TEST(testExistNotExist); + CPPUNIT_TEST(testCreateNotCreate); + CPPUNIT_TEST(testLockUnlock); + CPPUNIT_TEST(testWriteRead); + CPPUNIT_TEST(testSeek); + CPPUNIT_TEST_SUITE_END(); + +public: + void testExistNotExist(); + void testCreateNotCreate(); + void testLockUnlock(); + void testWriteRead(); + void testSeek(); + + void setUp(); + void tearDown(); + +private: + bool exists(std::string path); +}; + +#endif // !_SOFTHSM_V2_FILETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/Makefile.am b/SoftHSMv2/src/lib/object_store/test/Makefile.am new file mode 100644 index 0000000..71de7dd --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/Makefile.am @@ -0,0 +1,39 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../../common \ + -I$(srcdir)/../../crypto \ + -I$(srcdir)/../../data_mgr \ + -I$(srcdir)/../../pkcs11 \ + -I$(srcdir)/../../session_mgr \ + -I$(srcdir)/../../slot_mgr \ + @CPPUNIT_CFLAGS@ \ + @CRYPTO_INCLUDES@ + +check_PROGRAMS = objstoretest + +objstoretest_SOURCES = objstoretest.cpp \ + DirectoryTests.cpp \ + UUIDTests.cpp \ + FileTests.cpp \ + ObjectFileTests.cpp \ + OSTokenTests.cpp \ + ObjectStoreTests.cpp \ + SessionObjectTests.cpp \ + SessionObjectStoreTests.cpp + +if BUILD_OBJECTSTORE_BACKEND_DB +objstoretest_SOURCES += DBTests.cpp \ + DBObjectTests.cpp \ + DBTokenTests.cpp \ + DBObjectStoreTests.cpp +endif + +objstoretest_LDADD = ../../libsofthsm_convarch.la + +objstoretest_LDFLAGS = @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread + +TESTS = objstoretest + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp new file mode 100644 index 0000000..5afd583 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + OSTokenTests.cpp + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#include +#include +#include +#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 objects = existingToken.getObjects(); + + for (std::set::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 objects = testToken->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set::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 otherObjects = sameToken.getObjects(); + CPPUNIT_ASSERT(otherObjects.size() == 3); + + bool present2[3] = { false, false, false }; + + for (std::set::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::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::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::iterator i = otherObjects.begin(); i != otherObjects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present4[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present4[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present4[j] == true); + } + + + // Release the test token + delete testToken; +} + +void OSTokenTests::testClearToken() +{ + // Create a new token + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + +#ifndef _WIN32 + OSToken* newToken = OSToken::createToken("./testdir", "newToken", label, serial); +#else + OSToken* newToken = OSToken::createToken(".\\testdir", "newToken", label, serial); +#endif + + CPPUNIT_ASSERT(newToken != NULL); + + // Check the flags + CK_ULONG flags; + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED)); + + // Set the SO PIN + ByteString soPIN = "3132333435363738"; // 12345678 + + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + + // Set the user PIN + ByteString userPIN = "31323334"; // 1234 + + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + delete newToken; + + // Now reopen the newly created token +#ifndef _WIN32 + OSToken reopenedToken("./testdir/newToken"); +#else + OSToken reopenedToken(".\\testdir\\newToken"); +#endif + + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Retrieve the flags, user PIN and so PIN + ByteString retrievedSOPIN, retrievedUserPIN; + + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + // Now reset the token + CPPUNIT_ASSERT(reopenedToken.resetToken(label)); + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(!reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED)); + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Now clear the token + CPPUNIT_ASSERT(reopenedToken.clearToken()); + CPPUNIT_ASSERT(!reopenedToken.isValid()); + + // Try to open it once more +#ifndef _WIN32 + OSToken clearedToken("./testdir/newToken"); +#else + OSToken clearedToken(".\\testdir\\newToken"); +#endif + + CPPUNIT_ASSERT(!clearedToken.isValid()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h new file mode 100644 index 0000000..1155fcf --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + OSTokenTests.h + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OSTOKENTESTS_H +#define _SOFTHSM_V2_OSTOKENTESTS_H + +#include + +class OSTokenTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(OSTokenTests); + CPPUNIT_TEST(testNewToken); + CPPUNIT_TEST(testExistingToken); + CPPUNIT_TEST(testNonExistentToken); + CPPUNIT_TEST(testCreateDeleteObjects); + CPPUNIT_TEST(testClearToken); + CPPUNIT_TEST_SUITE_END(); + +public: + void testNewToken(); + void testExistingToken(); + void testNonExistentToken(); + void testCreateDeleteObjects(); + void testClearToken(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OSTOKENTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp new file mode 100644 index 0000000..9f0f5bd --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectObjectFileTests.cpp + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#include +#include +#include +#include +#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 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 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 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 mattr; + mattr.insert(std::pair (CKA_TOKEN, attr1)); + mattr.insert(std::pair (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair (CKA_VALUE, attr3)); + mattr.insert(std::pair (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 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 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 value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set 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 value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set 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 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 value4a; + value4a.insert(CKM_SHA384); + value4a.insert(CKM_SHA512); + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + OSAttribute attr4a(value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4a)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + // Commit the transaction + CPPUNIT_ASSERT(testObject.commitTransaction()); + + // Verify that they have now changed on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Abort the transaction + CPPUNIT_ASSERT(testObject.abortTransaction()); + + // Verify that they are unchanged on both instances + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); +} + +void ObjectFileTests::testDestroyObjectFails() +{ + // Create test object instance +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + OSObject* testIF = (OSObject*) &testObject; + + CPPUNIT_ASSERT(!testIF->destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h new file mode 100644 index 0000000..8342a64 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectFileTests.h + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OBJECTFILETESTS_H +#define _SOFTHSM_V2_OBJECTFILETESTS_H + +#include + +class ObjectFileTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ObjectFileTests); + CPPUNIT_TEST(testBoolAttr); + CPPUNIT_TEST(testULongAttr); + CPPUNIT_TEST(testByteStrAttr); + CPPUNIT_TEST(testMechTypeSetAttr); + CPPUNIT_TEST(testAttrMapAttr); + CPPUNIT_TEST(testMixedAttr); + CPPUNIT_TEST(testDoubleAttr); + CPPUNIT_TEST(testRefresh); + CPPUNIT_TEST(testCorruptFile); + CPPUNIT_TEST(testTransactions); + CPPUNIT_TEST(testDestroyObjectFails); + CPPUNIT_TEST_SUITE_END(); + +public: + void testBoolAttr(); + void testULongAttr(); + void testByteStrAttr(); + void testMechTypeSetAttr(); + void testAttrMapAttr(); + void testMixedAttr(); + void testDoubleAttr(); + void testRefresh(); + void testCorruptFile(); + void testTransactions(); + void testDestroyObjectFails(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OBJECTFILETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp new file mode 100644 index 0000000..0cad27b --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectStoreTests.cpp + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#include +#include +#include +#include "ObjectStoreTests.h" +#include "ObjectStore.h" +#include "File.h" +#include "Directory.h" +#include "OSAttribute.h" +#include "OSAttributes.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStoreTests); + +// FIXME: all pathnames in this file are *NIX/BSD specific + +void ObjectStoreTests::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void ObjectStoreTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void ObjectStoreTests::testEmptyStore() +{ + // Create the store for an empty dir +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 0); +} + +void ObjectStoreTests::testNewTokens() +{ + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + { + // Create an empty store +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 0); + + // Create a new token + ObjectStoreToken* token1 = store.newToken(label1); + + CPPUNIT_ASSERT(token1 != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 1); + + // Create another new token + ObjectStoreToken* token2 = store.newToken(label2); + + CPPUNIT_ASSERT(token2 != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + } + + // Now reopen that same store +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store.getToken(0); + ObjectStoreToken* token2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2; + + CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel2 == label1)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + + ByteString retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} + +void ObjectStoreTests::testExistingTokens() +{ + // Create some tokens + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + ByteString serial1 = "0011001100110011"; + ByteString serial2 = "2233223322332233"; + +#ifndef _WIN32 + ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2); +#else + ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2); +#endif + + CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL)); + + delete token1; + delete token2; + + // Now associate a store with the test directory +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1 = store.getToken(0); + ObjectStoreToken* retrieveToken2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(retrieveToken1 != NULL); + CPPUNIT_ASSERT(retrieveToken2 != NULL); + + CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); + CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2)); + CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2)); + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} + +void ObjectStoreTests::testDeleteToken() +{ + // Create some tokens + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + ByteString serial1 = "0011001100110011"; + ByteString serial2 = "2233223322332233"; + +#ifndef _WIN32 + ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2); +#else + ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2); +#endif + + CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL)); + + delete token1; + delete token2; + + // Now associate a store with the test directory +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1 = store.getToken(0); + ObjectStoreToken* retrieveToken2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(retrieveToken1 != NULL); + CPPUNIT_ASSERT(retrieveToken2 != NULL); + + CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); + CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2)); + CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2)); + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); + + // Now, delete token #1 + CPPUNIT_ASSERT(store.destroyToken(retrieveToken1)); + + CPPUNIT_ASSERT(store.getTokenCount() == 1); + + ObjectStoreToken* retrieveToken_ = store.getToken(0); + + ByteString retrieveLabel_,retrieveSerial_; + + CPPUNIT_ASSERT(retrieveToken_->getTokenLabel(retrieveLabel_)); + CPPUNIT_ASSERT(retrieveToken_->getTokenSerial(retrieveSerial_)); + + CPPUNIT_ASSERT(((retrieveLabel_ == label1) && (retrieveSerial_ == serial1)) || + ((retrieveLabel_ == label2) && (retrieveSerial_ == serial2))); + + // Now add a new token + ByteString label3 = "DEADC0FFEEBEEF"; + + // Create a new token + ObjectStoreToken* tokenNew = store.newToken(label3); + + CPPUNIT_ASSERT(tokenNew != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1_ = store.getToken(0); + ObjectStoreToken* retrieveToken2_ = store.getToken(1); + + CPPUNIT_ASSERT(retrieveToken1_ != NULL); + CPPUNIT_ASSERT(retrieveToken2_ != NULL); + + CPPUNIT_ASSERT(retrieveToken1_->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2_->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1_->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2_->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label3) || (retrieveLabel2 == label3)); + CPPUNIT_ASSERT(((retrieveLabel1 == label1) && (retrieveLabel2 != label2)) || + ((retrieveLabel1 == label2) && (retrieveLabel2 != label1))); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h new file mode 100644 index 0000000..3f03c5a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectStoreTests.h + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OBJECTSTORETESTS_H +#define _SOFTHSM_V2_OBJECTSTORETESTS_H + +#include + +class ObjectStoreTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ObjectStoreTests); + CPPUNIT_TEST(testEmptyStore); + CPPUNIT_TEST(testNewTokens); + CPPUNIT_TEST(testExistingTokens); + CPPUNIT_TEST(testDeleteToken); + CPPUNIT_TEST_SUITE_END(); + +public: + void testEmptyStore(); + void testNewTokens(); + void testExistingTokens(); + void testDeleteToken(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OBJECTSTORETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp new file mode 100644 index 0000000..2c41eb0 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectStoreTests.cpp + + Contains test cases to test the session object store implementation + *****************************************************************************/ + +#include +#include +#include +#include +#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 objects = testStore->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set::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::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::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 objects = store->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set::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::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present3[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present3[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present3[j] == true); + } + + // Create two more objects for session 7 + SessionObject* obj4 = store->createObject(1, 7); + CPPUNIT_ASSERT(obj4 != NULL); + SessionObject* obj5 = store->createObject(1, 7); + CPPUNIT_ASSERT(obj5 != NULL); + + CPPUNIT_ASSERT(store->getObjects().size() == 4); + + // Close session 1 + store->sessionClosed(1); + + CPPUNIT_ASSERT(store->getObjects().size() == 3); + + objects = store->getObjects(); + + CPPUNIT_ASSERT(objects.find(obj1) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj2) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj3) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj4) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj5) != objects.end()); + + CPPUNIT_ASSERT(!obj1->isValid()); + CPPUNIT_ASSERT(!obj2->isValid()); + CPPUNIT_ASSERT(obj3->isValid()); + CPPUNIT_ASSERT(obj4->isValid()); + CPPUNIT_ASSERT(obj5->isValid()); + + // Close session 7 + store->sessionClosed(7); + + CPPUNIT_ASSERT(store->getObjects().size() == 1); + + objects = store->getObjects(); + + CPPUNIT_ASSERT(objects.find(obj1) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj2) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj3) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj4) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj5) == objects.end()); + + CPPUNIT_ASSERT(!obj1->isValid()); + CPPUNIT_ASSERT(!obj2->isValid()); + CPPUNIT_ASSERT(obj3->isValid()); + CPPUNIT_ASSERT(!obj4->isValid()); + CPPUNIT_ASSERT(!obj5->isValid()); + + delete store; +} + +void SessionObjectStoreTests::testWipeStore() +{ + // Get access to the store + SessionObjectStore* store = new SessionObjectStore(); + + // Check that the store is empty + CPPUNIT_ASSERT(store->getObjects().size() == 0); + + // Create 3 objects in the store for three different sessions + SessionObject* obj1 = store->createObject(1, 1); + CPPUNIT_ASSERT(obj1 != NULL); + SessionObject* obj2 = store->createObject(1, 2); + CPPUNIT_ASSERT(obj2 != NULL); + SessionObject* obj3 = store->createObject(1, 3); + CPPUNIT_ASSERT(obj3 != NULL); + + // Wipe the store + store->clearStore(); + + // Check that the store is empty + CPPUNIT_ASSERT(store->getObjects().size() == 0); + + delete store; +} + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h new file mode 100644 index 0000000..374eeaa --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectStoreTests.h + + Contains test cases to test the session object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H +#define _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H + +#include + +class SessionObjectStoreTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SessionObjectStoreTests); + CPPUNIT_TEST(testCreateDeleteObjects); + CPPUNIT_TEST(testMultiSession); + CPPUNIT_TEST(testWipeStore); + CPPUNIT_TEST_SUITE_END(); + +public: + void testCreateDeleteObjects(); + void testMultiSession(); + void testWipeStore(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp new file mode 100644 index 0000000..6183ec6 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectTests.cpp + + Contains test cases to test the session object implementation + *****************************************************************************/ + +#include +#include +#include +#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 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 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 mattr; + mattr.insert(std::pair (CKA_TOKEN, attr1)); + mattr.insert(std::pair (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair (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 mattrb = + testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue(); + CPPUNIT_ASSERT(mattrb.size() == 3); + CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(mattrb.find(CKA_VALUE_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).isByteStringAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).getByteStringValue() == value3); + +} + +void SessionObjectTests::testMixedAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); +} + +void SessionObjectTests::testDoubleAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value3a = "466487346943785684957634"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); + + bool value1a = false; + unsigned long value2a = 0x76767676; + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3a); + + CPPUNIT_ASSERT(testObject.isValid()); +} + +void SessionObjectTests::testCloseSession() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); + + // Now close the session + testObject.removeOnSessionClose(1); + + CPPUNIT_ASSERT(!testObject.isValid()); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_VALUE_BITS)); +} + +void SessionObjectTests::testDestroyObjectFails() +{ + // Create test object instance + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + OSObject* testIF = (OSObject*) &testObject; + + CPPUNIT_ASSERT(!testIF->destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h new file mode 100644 index 0000000..76fa02e --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectTests.h + + Contains test cases to test the session object implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SESSIONOBJECTTESTS_H +#define _SOFTHSM_V2_SESSIONOBJECTTESTS_H + +#include + +class SessionObjectTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SessionObjectTests); + CPPUNIT_TEST(testBoolAttr); + CPPUNIT_TEST(testULongAttr); + CPPUNIT_TEST(testByteStrAttr); + CPPUNIT_TEST(testMechTypeSetAttr); + CPPUNIT_TEST(testAttrMapAttr); + CPPUNIT_TEST(testMixedAttr); + CPPUNIT_TEST(testDoubleAttr); + CPPUNIT_TEST(testCloseSession); + CPPUNIT_TEST(testDestroyObjectFails); + CPPUNIT_TEST_SUITE_END(); + +public: + void testBoolAttr(); + void testULongAttr(); + void testByteStrAttr(); + void testMechTypeSetAttr(); + void testAttrMapAttr(); + void testMixedAttr(); + void testDoubleAttr(); + void testCloseSession(); + void testDestroyObjectFails(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_SESSIONOBJECTTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp b/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp new file mode 100644 index 0000000..84a49d2 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + UUIDTests.cpp + + Contains test cases to test the UUID implementation + *****************************************************************************/ + +#include +#include +#include +#include "UUIDTests.h" +#include "UUID.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(UUIDTests); + +void UUIDTests::setUp() +{ +} + +void UUIDTests::tearDown() +{ +} + +void UUIDTests::testUUID() +{ + std::string uuid1 = UUID::newUUID(); + std::string uuid2 = UUID::newUUID(); + std::string uuid3 = UUID::newUUID(); + + CPPUNIT_ASSERT((uuid1.size() == 36) && (uuid2.size() == 36) && (uuid3.size() == 36)); + + CPPUNIT_ASSERT(uuid1.compare(uuid2)); + CPPUNIT_ASSERT(uuid1.compare(uuid3)); + CPPUNIT_ASSERT(uuid2.compare(uuid3)); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.h b/SoftHSMv2/src/lib/object_store/test/UUIDTests.h new file mode 100644 index 0000000..374d509 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/UUIDTests.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + UUIDTests.h + + Contains test cases to test the UUID implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_UUIDTESTS_H +#define _SOFTHSM_V2_UUIDTESTS_H + +#include + +class UUIDTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(UUIDTests); + CPPUNIT_TEST(testUUID); + CPPUNIT_TEST_SUITE_END(); + +public: + void testUUID(); + + void setUp(); + void tearDown(); + +private: +}; + +#endif // !_SOFTHSM_V2_UUIDTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp b/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp new file mode 100644 index 0000000..7e4b854 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + objstoretest.cpp + + The main test executor for tests on the object store in SoftHSM v2 + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#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::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr BotanCryptoFactory::instance(NULL); +#endif + +#endif + +int main(int /*argc*/, char** /*argv*/) +{ + CppUnit::TestResult controller; + CppUnit::TestResultCollector result; + CppUnit::TextUi::TestRunner runner; + controller.addListener(&result); + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/SoftHSMv2/src/lib/pkcs11/cryptoki.h b/SoftHSMv2/src/lib/pkcs11/cryptoki.h new file mode 100644 index 0000000..d278b42 --- /dev/null +++ b/SoftHSMv2/src/lib/pkcs11/cryptoki.h @@ -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 index 0000000..0d78dd7 --- /dev/null +++ b/SoftHSMv2/src/lib/pkcs11/pkcs11.h @@ -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 index 0000000..ed90aff --- /dev/null +++ b/SoftHSMv2/src/lib/pkcs11/pkcs11f.h @@ -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 index 0000000..0cf3acc --- /dev/null +++ b/SoftHSMv2/src/lib/pkcs11/pkcs11t.h @@ -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 index 0000000..5186d33 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/Makefile.am @@ -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 index 0000000..5db36fd --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/Session.cpp @@ -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 index 0000000..142aaa5 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/Session.h @@ -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 index 0000000..b665210 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/SessionManager.cpp @@ -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 toDelete = sessions; + sessions.clear(); + + for (std::vector::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::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::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::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 index 0000000..1091782 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/SessionManager.h @@ -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 +#include + +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 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 index 0000000..6395038 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/test/Makefile.am @@ -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 index 0000000..2c2e51a --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.cpp @@ -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 +#include +#include +#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 index 0000000..23f9d8c --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/test/SessionManagerTests.h @@ -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 + +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 index 0000000..28eeee8 --- /dev/null +++ b/SoftHSMv2/src/lib/session_mgr/test/sessionmgrtest.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr 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 ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/SoftHSMv2/src/lib/slot_mgr/Makefile.am b/SoftHSMv2/src/lib/slot_mgr/Makefile.am new file mode 100644 index 0000000..1e8cf33 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/Makefile.am @@ -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 index 0000000..fea260b --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/Slot.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 +#include +#include + +// 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 index 0000000..6ab07c6 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/Slot.h @@ -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 +#include + +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 index 0000000..1f96909 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/SlotManager.cpp @@ -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 +#include +typedef std::pair SlotMapElement; +typedef std::pair 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 index 0000000..04f51c0 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/SlotManager.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + 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 +#include +typedef std::map 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 index 0000000..b4c9401 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/Token.cpp @@ -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 + +#ifndef _WIN32 +#include +#else +#include +#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 &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 index 0000000..8f67433 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/Token.h @@ -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 +#include + +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 &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 index 0000000..8e2d161 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/test/Makefile.am @@ -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 index 0000000..c5f6687 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.cpp @@ -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 +#include +#include +#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 index 0000000..8d4e57f --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/test/SlotManagerTests.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SlotManagerTests.h + + Contains test cases to test the slot manager implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SLOTMANAGERTESTS_H +#define _SOFTHSM_V2_SLOTMANAGERTESTS_H + +#include + +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 index 0000000..4172b63 --- /dev/null +++ b/SoftHSMv2/src/lib/slot_mgr/test/slotmgrtest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + slotmgrtest.cpp + + The main test executor for tests on the slot manager in SoftHSM v2 + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#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::instance(nullptr); +std::unique_ptr SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr MutexFactory::instance(NULL); +std::auto_ptr SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr BotanCryptoFactory::instance(NULL); +#endif + +#endif + +int main(int /*argc*/, char** /*argv*/) +{ + CppUnit::TestResult controller; + CppUnit::TestResultCollector result; + CppUnit::TextUi::TestRunner runner; + controller.addListener(&result); + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} diff --git a/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp b/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp new file mode 100644 index 0000000..6f06a42 --- /dev/null +++ b/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.cpp @@ -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 +#include +#include +#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 index 0000000..0b8db04 --- /dev/null +++ b/SoftHSMv2/src/lib/test/AsymEncryptDecryptTests.h @@ -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 + +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 index 0000000..9614e69 --- /dev/null +++ b/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.cpp @@ -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 +#include +#include +#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 index 0000000..97f6940 --- /dev/null +++ b/SoftHSMv2/src/lib/test/AsymWrapUnwrapTests.h @@ -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 + +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 index 0000000..588d0b9 --- /dev/null +++ b/SoftHSMv2/src/lib/test/DeriveTests.cpp @@ -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 +#include +#include +#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 = ¶m1; + 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 = ¶m2; + 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 = ¶m3; + 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 index 0000000..5b2aef5 --- /dev/null +++ b/SoftHSMv2/src/lib/test/DeriveTests.h @@ -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 + +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 index 0000000..b5e7e7e --- /dev/null +++ b/SoftHSMv2/src/lib/test/DigestTests.cpp @@ -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 +#include +#include +#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 index 0000000..e724a39 --- /dev/null +++ b/SoftHSMv2/src/lib/test/DigestTests.h @@ -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 + +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 index 0000000..958d96e --- /dev/null +++ b/SoftHSMv2/src/lib/test/InfoTests.cpp @@ -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 +#include +#include +#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 index 0000000..4acf770 --- /dev/null +++ b/SoftHSMv2/src/lib/test/InfoTests.h @@ -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 + +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 index 0000000..71611f8 --- /dev/null +++ b/SoftHSMv2/src/lib/test/InitTests.cpp @@ -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 +#include +#include +#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 index 0000000..ba22ec0 --- /dev/null +++ b/SoftHSMv2/src/lib/test/InitTests.h @@ -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 +#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 index 0000000..4345878 --- /dev/null +++ b/SoftHSMv2/src/lib/test/Makefile.am @@ -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 index 0000000..cd6c676 --- /dev/null +++ b/SoftHSMv2/src/lib/test/ObjectTests.cpp @@ -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 +#include +#include +#include "ObjectTests.h" + +// Common object attributes +const CK_BBOOL CKA_TOKEN_DEFAULT = CK_FALSE; +//const CK_BBOOL CKA_PRIVATE_DEFAULT = +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 index 0000000..b15ae48 --- /dev/null +++ b/SoftHSMv2/src/lib/test/ObjectTests.h @@ -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 + +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 index 0000000..d9e6cce --- /dev/null +++ b/SoftHSMv2/src/lib/test/README @@ -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 index 0000000..8fe25bc --- /dev/null +++ b/SoftHSMv2/src/lib/test/RandomTests.cpp @@ -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 +#include +#include +#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 index 0000000..4b7b062 --- /dev/null +++ b/SoftHSMv2/src/lib/test/RandomTests.h @@ -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 + +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 index 0000000..756106a --- /dev/null +++ b/SoftHSMv2/src/lib/test/SessionTests.cpp @@ -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 +#include +#include +#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 index 0000000..c940ab0 --- /dev/null +++ b/SoftHSMv2/src/lib/test/SessionTests.h @@ -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 + +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 index 0000000..06dbf95 --- /dev/null +++ b/SoftHSMv2/src/lib/test/SignVerifyTests.cpp @@ -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 +#include +#include +#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 + +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 index 0000000..f301c73 --- /dev/null +++ b/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.cpp @@ -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 +#include +#include +#include +//#include +#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* 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 vData(messageSize); + std::vector vEncryptedData; + std::vector 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::const_iterator i(vData.begin()); i0 ? &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 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 vDecryptedData; + CK_BYTE dummy; + for ( std::vector::iterator i(vEncryptedDataParted.begin()); i0 ? &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 vEncryptedData; + std::vector vEncryptedDataParted; + std::vector vDecryptedData; + std::vector 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 index 0000000..9b96ae1 --- /dev/null +++ b/SoftHSMv2/src/lib/test/SymmetricAlgorithmTests.h @@ -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 + +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 index 0000000..1c8467c --- /dev/null +++ b/SoftHSMv2/src/lib/test/TestsBase.cpp @@ -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 + +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 index 0000000..6bcf894 --- /dev/null +++ b/SoftHSMv2/src/lib/test/TestsBase.h @@ -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 + +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 index 0000000..f5bb066 --- /dev/null +++ b/SoftHSMv2/src/lib/test/TestsNoPINInitBase.cpp @@ -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 +#include +#include +#include + +#ifdef P11M +#ifdef _WIN32 +CK_FUNCTION_LIST_PTR FunctionList::getFunctionListPtr(const char*const libName, HINSTANCE__* p11Library, const char*getFunctionList) { +#else +#include + +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 slotIDs(nrOfSlots); + CPPUNIT_ASSERT( CRYPTOKI_F_PTR( C_GetSlotList(CK_TRUE, &slotIDs.front(), &nrOfSlots)==CKR_OK ) ); + for ( std::vector::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 index 0000000..acce9f1 --- /dev/null +++ b/SoftHSMv2/src/lib/test/TestsNoPINInitBase.h @@ -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 + + +#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 index 0000000..9fc77ba --- /dev/null +++ b/SoftHSMv2/src/lib/test/TokenTests.cpp @@ -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 +#include +#include +#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 index 0000000..cc08b72 --- /dev/null +++ b/SoftHSMv2/src/lib/test/TokenTests.h @@ -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 + +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 index 0000000..d4999e5 --- /dev/null +++ b/SoftHSMv2/src/lib/test/UserTests.cpp @@ -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 +#include +#include +#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 index 0000000..9104208 --- /dev/null +++ b/SoftHSMv2/src/lib/test/UserTests.h @@ -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 + +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 index 0000000..1198c91 --- /dev/null +++ b/SoftHSMv2/src/lib/test/p11test.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 ®istry( 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 index 0000000..5bdcb1f --- /dev/null +++ b/SoftHSMv2/src/lib/test/softhsm2-alt.conf.in @@ -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 index 0000000..68cb2ec --- /dev/null +++ b/SoftHSMv2/src/lib/test/softhsm2-alt.conf.win32 @@ -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 index 0000000..6554669 --- /dev/null +++ b/SoftHSMv2/src/lib/test/softhsm2.conf.in @@ -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 index 0000000..a877d1f --- /dev/null +++ b/SoftHSMv2/src/lib/test/softhsm2.conf.win32 @@ -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 index 0000000..e69de29 diff --git a/SoftHSMv2/src/lib/win32/dllmain.cc b/SoftHSMv2/src/lib/win32/dllmain.cc new file mode 100644 index 0000000..359227d --- /dev/null +++ b/SoftHSMv2/src/lib/win32/dllmain.cc @@ -0,0 +1,18 @@ +#include + +__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 index 0000000..da41a62 --- /dev/null +++ b/SoftHSMv2/src/lib/win32/setenv.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +#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 index 0000000..e199227 --- /dev/null +++ b/SoftHSMv2/src/lib/win32/setenv.h @@ -0,0 +1,12 @@ +#include + +#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 index 0000000..927592e --- /dev/null +++ b/SoftHSMv2/src/lib/win32/syslog.cpp @@ -0,0 +1,69 @@ +#include + +#include +#include +#include +#include +#include + +#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 index 0000000..1ed207c --- /dev/null +++ b/SoftHSMv2/src/lib/win32/syslog.h @@ -0,0 +1,46 @@ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include + +/* 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 -- cgit 1.2.3-korg