aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/lib/slot_mgr/Token.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/lib/slot_mgr/Token.cpp')
-rw-r--r--SoftHSMv2/src/lib/slot_mgr/Token.cpp573
1 files changed, 573 insertions, 0 deletions
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 <cstdio>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+// Constructor
+Token::Token()
+{
+ tokenMutex = MutexFactory::i()->getMutex();
+
+ token = NULL;
+ sdm = NULL;
+ valid = false;
+}
+
+// Constructor
+Token::Token(ObjectStoreToken* inToken)
+{
+ tokenMutex = MutexFactory::i()->getMutex();
+
+ token = inToken;
+
+ ByteString soPINBlob, userPINBlob;
+
+ valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+ sdm = new SecureDataManager(soPINBlob, userPINBlob);
+}
+
+// Destructor
+Token::~Token()
+{
+ if (sdm != NULL) delete sdm;
+
+ MutexFactory::i()->recycleMutex(tokenMutex);
+}
+
+// Check if the token is still valid
+bool Token::isValid()
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ return (valid && token->isValid());
+}
+
+// Check if the token is initialized
+bool Token::isInitialized()
+{
+ if (token == NULL) return false;
+
+ return true;
+}
+
+// Check if SO is logged in
+bool Token::isSOLoggedIn()
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return false;
+
+ return sdm->isSOLoggedIn();
+}
+
+// Check if user is logged in
+bool Token::isUserLoggedIn()
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return false;
+
+ return sdm->isUserLoggedIn();
+}
+
+// Login SO
+CK_RV Token::loginSO(ByteString& pin)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ // User cannot be logged in
+ if (sdm->isUserLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+ // SO cannot be logged in
+ if (sdm->isSOLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;
+
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Login
+ if (!sdm->loginSO(pin))
+ {
+ flags |= CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_PIN_INCORRECT;
+ }
+
+ flags &= ~CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_OK;
+}
+
+// Login user
+CK_RV Token::loginUser(ByteString& pin)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ // SO cannot be logged in
+ if (sdm->isSOLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+ // User cannot be logged in
+ if (sdm->isUserLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;
+
+ // The user PIN has to be initialized;
+ if (sdm->getUserPINBlob().size() == 0) return CKR_USER_PIN_NOT_INITIALIZED;
+
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Login
+ if (!sdm->loginUser(pin))
+ {
+ flags |= CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_PIN_INCORRECT;
+ }
+
+ flags &= ~CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_OK;
+}
+
+CK_RV Token::reAuthenticate(ByteString& pin)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ if (sdm->isSOLoggedIn())
+ {
+ // Login
+ if (!sdm->reAuthenticateSO(pin))
+ {
+ flags |= CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_PIN_INCORRECT;
+ }
+ else
+ {
+ flags &= ~CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ }
+ }
+ else if (sdm->isUserLoggedIn())
+ {
+ // Login
+ if (!sdm->reAuthenticateUser(pin))
+ {
+ flags |= CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_PIN_INCORRECT;
+ }
+ else
+ {
+ flags &= ~CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ }
+ }
+ else
+ {
+ return CKR_OPERATION_NOT_INITIALIZED;
+ }
+
+ return CKR_OK;
+}
+
+// Logout any user on this token;
+void Token::logout()
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return;
+
+ sdm->logout();
+}
+
+// Change SO PIN
+CK_RV Token::setSOPIN(ByteString& oldPIN, ByteString& newPIN)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Verify oldPIN
+ SecureDataManager* verifier = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
+ bool result = verifier->loginSO(oldPIN);
+ delete verifier;
+ if (result == false)
+ {
+ flags |= CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ return CKR_PIN_INCORRECT;
+ }
+
+ if (sdm->setSOPIN(newPIN) == false) return CKR_GENERAL_ERROR;
+
+ // Save PIN to token file
+ if (token->setSOPIN(sdm->getSOPINBlob()) == false) return CKR_GENERAL_ERROR;
+
+ ByteString soPINBlob, userPINBlob;
+ valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+ flags &= ~CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+
+ return CKR_OK;
+}
+
+// Change the user PIN
+CK_RV Token::setUserPIN(ByteString& oldPIN, ByteString& newPIN)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ // Check if user should stay logged in
+ bool stayLoggedIn = sdm->isUserLoggedIn();
+
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Verify oldPIN
+ SecureDataManager* newSdm = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
+ if (newSdm->loginUser(oldPIN) == false)
+ {
+ flags |= CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+ delete newSdm;
+ return CKR_PIN_INCORRECT;
+ }
+
+ // Set the new user PIN
+ if (newSdm->setUserPIN(newPIN) == false)
+ {
+ delete newSdm;
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Save PIN to token file
+ if (token->setUserPIN(newSdm->getUserPINBlob()) == false)
+ {
+ delete newSdm;
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Restore previous login state
+ if (!stayLoggedIn) newSdm->logout();
+
+ // Switch sdm
+ delete sdm;
+ sdm = newSdm;
+
+ ByteString soPINBlob, userPINBlob;
+ valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+ flags &= ~CKF_USER_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+
+ return CKR_OK;
+}
+
+// Init the user PIN
+CK_RV Token::initUserPIN(ByteString& pin)
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return CKR_GENERAL_ERROR;
+
+ if (sdm->setUserPIN(pin) == false) return CKR_GENERAL_ERROR;
+
+ // Save PIN to token file
+ if (token->setUserPIN(sdm->getUserPINBlob()) == false) return CKR_GENERAL_ERROR;
+
+ ByteString soPINBlob, userPINBlob;
+ valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+ return CKR_OK;
+}
+
+// Create a new token
+CK_RV Token::createToken(ObjectStore* objectStore, ByteString& soPIN, CK_UTF8CHAR_PTR label)
+{
+ CK_ULONG flags;
+
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (objectStore == NULL) return CKR_GENERAL_ERROR;
+ if (label == NULL_PTR) return CKR_ARGUMENTS_BAD;
+
+ // Convert the label
+ ByteString labelByteStr((const unsigned char*) label, 32);
+
+ if (token != NULL)
+ {
+ // Get token flags
+ if (!token->getTokenFlags(flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Verify SO PIN
+ if (sdm->getSOPINBlob().size() > 0 && !sdm->loginSO(soPIN))
+ {
+ flags |= CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+
+ ERROR_MSG("Incorrect SO PIN");
+ return CKR_PIN_INCORRECT;
+ }
+ flags &= ~CKF_SO_PIN_COUNT_LOW;
+ token->setTokenFlags(flags);
+
+ // Reset the token
+ if (!token->resetToken(labelByteStr))
+ {
+ ERROR_MSG("Could not reset the token");
+ return CKR_DEVICE_ERROR;
+ }
+ }
+ else
+ {
+ // Generate the SO PIN blob
+ SecureDataManager soPINBlobGen;
+
+ if (!soPINBlobGen.setSOPIN(soPIN))
+ {
+ return CKR_GENERAL_ERROR;
+ }
+
+ // Create the token
+ ObjectStoreToken* newToken = objectStore->newToken(labelByteStr);
+
+ if (newToken == NULL)
+ {
+ ERROR_MSG("Could not create the token");
+ return CKR_DEVICE_ERROR;
+ }
+
+ // Set the SO PIN on the token
+ if (!newToken->setSOPIN(soPINBlobGen.getSOPINBlob()))
+ {
+ ERROR_MSG("Failed to set SO PIN on new token");
+
+ if (!objectStore->destroyToken(newToken))
+ {
+ ERROR_MSG("Failed to destroy incomplete token");
+ }
+
+ return CKR_DEVICE_ERROR;
+ }
+
+ token = newToken;
+ }
+
+ ByteString soPINBlob, userPINBlob;
+
+ valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);
+
+ if (sdm != NULL) delete sdm;
+ sdm = new SecureDataManager(soPINBlob, userPINBlob);
+
+ return CKR_OK;
+}
+
+// Retrieve token information for the token
+CK_RV Token::getTokenInfo(CK_TOKEN_INFO_PTR info)
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ ByteString label, serial;
+
+ if (info == NULL)
+ {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ memset(info->label, ' ', 32);
+ memset(info->serialNumber, ' ', 16);
+
+ // Token specific information
+ if (token)
+ {
+ if (!token->getTokenFlags(info->flags))
+ {
+ ERROR_MSG("Could not get the token flags");
+ return CKR_GENERAL_ERROR;
+ }
+
+ if (token->getTokenLabel(label))
+ {
+ strncpy((char*) info->label, (char*) label.byte_str(), label.size());
+ }
+
+ if (token->getTokenSerial(serial))
+ {
+ strncpy((char*) info->serialNumber, (char*) serial.byte_str(), serial.size());
+ }
+ }
+ else
+ {
+ info->flags = CKF_RNG |
+ CKF_LOGIN_REQUIRED |
+ CKF_RESTORE_KEY_NOT_NEEDED |
+ CKF_SO_PIN_LOCKED |
+ CKF_SO_PIN_TO_BE_CHANGED;
+ }
+
+ // Information shared by all tokens
+ char mfgID[33];
+ char model[17];
+
+ snprintf(mfgID, 33, "SoftHSM project");
+ snprintf(model, 17, "SoftHSM v2");
+
+ memset(info->manufacturerID, ' ', 32);
+ memset(info->model, ' ', 16);
+ memcpy(info->manufacturerID, mfgID, strlen(mfgID));
+ memcpy(info->model, model, strlen(model));
+
+ // TODO: Can we set these?
+ info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
+ info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
+
+ info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulMaxPinLen = MAX_PIN_LEN;
+ info->ulMinPinLen = MIN_PIN_LEN;
+ info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ info->hardwareVersion.major = VERSION_MAJOR;
+ info->hardwareVersion.minor = VERSION_MINOR;
+ info->firmwareVersion.major = VERSION_MAJOR;
+ info->firmwareVersion.minor = VERSION_MINOR;
+
+ // Current time
+ time_t rawtime;
+ time(&rawtime);
+ char dateTime[17];
+ strftime(dateTime, 17, "%Y%m%d%H%M%S00", gmtime(&rawtime));
+ memcpy(info->utcTime, dateTime, 16);
+
+ return CKR_OK;
+}
+
+// Create an object
+OSObject* Token::createObject()
+{
+ return token->createObject();
+}
+
+void Token::getObjects(std::set<OSObject *> &objects)
+{
+ token->getObjects(objects);
+}
+
+bool Token::decrypt(const ByteString &encrypted, ByteString &plaintext)
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return false;
+
+ return sdm->decrypt(encrypted,plaintext);
+}
+
+bool Token::encrypt(const ByteString &plaintext, ByteString &encrypted)
+{
+ // Lock access to the token
+ MutexLocker lock(tokenMutex);
+
+ if (sdm == NULL) return false;
+
+ return sdm->encrypt(plaintext,encrypted);
+}