aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Neus <[email protected]>2016-06-17 11:37:18 +0200
committerDaniel Neus <[email protected]>2016-06-17 16:19:40 +0200
commit2ea6f9b1963795dad74489b41bc7d37f897d7a21 (patch)
treec9120503521633ee4a25ac2021b392f33d82e8d7
parent601f8f6d6075ff2f944c11d357f2309da0c4deb1 (diff)
add PKCS#11 support
-rw-r--r--src/lib/cert/x509/x509cert.h2
-rw-r--r--src/lib/prov/pkcs11/info.txt43
-rw-r--r--src/lib/prov/pkcs11/p11.cpp769
-rw-r--r--src/lib/prov/pkcs11/p11.h2861
-rw-r--r--src/lib/prov/pkcs11/p11_ecc_key.cpp137
-rw-r--r--src/lib/prov/pkcs11/p11_ecc_key.h229
-rw-r--r--src/lib/prov/pkcs11/p11_ecdh.cpp151
-rw-r--r--src/lib/prov/pkcs11/p11_ecdh.h122
-rw-r--r--src/lib/prov/pkcs11/p11_ecdsa.cpp239
-rw-r--r--src/lib/prov/pkcs11/p11_ecdsa.h127
-rw-r--r--src/lib/prov/pkcs11/p11_mechanism.cpp250
-rw-r--r--src/lib/prov/pkcs11/p11_mechanism.h108
-rw-r--r--src/lib/prov/pkcs11/p11_module.cpp41
-rw-r--r--src/lib/prov/pkcs11/p11_module.h79
-rw-r--r--src/lib/prov/pkcs11/p11_object.cpp217
-rw-r--r--src/lib/prov/pkcs11/p11_object.h743
-rw-r--r--src/lib/prov/pkcs11/p11_randomgenerator.cpp31
-rw-r--r--src/lib/prov/pkcs11/p11_randomgenerator.h70
-rw-r--r--src/lib/prov/pkcs11/p11_rsa.cpp382
-rw-r--r--src/lib/prov/pkcs11/p11_rsa.h213
-rw-r--r--src/lib/prov/pkcs11/p11_session.cpp89
-rw-r--r--src/lib/prov/pkcs11/p11_session.h105
-rw-r--r--src/lib/prov/pkcs11/p11_slot.cpp60
-rw-r--r--src/lib/prov/pkcs11/p11_slot.h79
-rw-r--r--src/lib/prov/pkcs11/p11_x509.cpp37
-rw-r--r--src/lib/prov/pkcs11/p11_x509.h115
-rw-r--r--src/lib/utils/dyn_load/dyn_load.cpp2
-rw-r--r--src/lib/utils/dyn_load/dyn_load.h3
-rw-r--r--src/lib/utils/dyn_load/info.txt12
-rw-r--r--src/tests/main.cpp28
-rw-r--r--src/tests/test_pkcs11.cpp42
-rw-r--r--src/tests/test_pkcs11.h50
-rw-r--r--src/tests/test_pkcs11_high_level.cpp1509
-rw-r--r--src/tests/test_pkcs11_low_level.cpp852
-rw-r--r--src/tests/tests.cpp37
-rw-r--r--src/tests/tests.h39
36 files changed, 9829 insertions, 44 deletions
diff --git a/src/lib/cert/x509/x509cert.h b/src/lib/cert/x509/x509cert.h
index c521cf7ca..2875c8159 100644
--- a/src/lib/cert/x509/x509cert.h
+++ b/src/lib/cert/x509/x509cert.h
@@ -33,7 +33,7 @@ enum class Usage_Type
/**
* This class represents X.509 Certificate
*/
-class BOTAN_DLL X509_Certificate final : public X509_Object
+class BOTAN_DLL X509_Certificate : public X509_Object
{
public:
/**
diff --git a/src/lib/prov/pkcs11/info.txt b/src/lib/prov/pkcs11/info.txt
new file mode 100644
index 000000000..4d54446da
--- /dev/null
+++ b/src/lib/prov/pkcs11/info.txt
@@ -0,0 +1,43 @@
+define PKCS11 20160219
+
+load_on vendor
+
+<requires>
+dyn_load
+rng
+pk_pad
+rfc6979
+</requires>
+
+<header:internal>
+p11_mechanism.h
+</header:internal>
+
+<header:public>
+p11.h
+p11_ecc_key.h
+p11_ecdh.h
+p11_ecdsa.h
+p11_module.h
+p11_object.h
+p11_randomgenerator.h
+p11_rsa.h
+p11_session.h
+p11_slot.h
+p11_x509.h
+</header:public>
+
+<source>
+p11.cpp
+p11_ecc_key.cpp
+p11_ecdh.cpp
+p11_ecdsa.cpp
+p11_mechanism.cpp
+p11_module.cpp
+p11_object.cpp
+p11_randomgenerator.cpp
+p11_rsa.cpp
+p11_session.cpp
+p11_slot.cpp
+p11_x509.cpp
+</source> \ No newline at end of file
diff --git a/src/lib/prov/pkcs11/p11.cpp b/src/lib/prov/pkcs11/p11.cpp
new file mode 100644
index 000000000..d338438d3
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11.cpp
@@ -0,0 +1,769 @@
+/*
+* PKCS#11
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+
+#include <cstdint>
+#include <string>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+ReturnValue* ThrowException = reinterpret_cast< ReturnValue* >(-1);
+
+namespace {
+/// @param function_result Return value of the PKCS11 module function
+/// @param returnValue if (`ThrowException`) is passed the function throws an exception, otherwise if a non-NULL pointer is passed:
+/// return_value receives the return value of the PKCS#11 function and no exception is thrown.
+/// @return true if function call was successful, false otherwise
+bool handle_return_value(const CK_RV function_result, ReturnValue* return_value)
+ {
+ if(return_value == ThrowException)
+ {
+ if(static_cast< ReturnValue >(function_result) != ReturnValue::OK)
+ {
+ // caller wants exception
+ throw PKCS11_ReturnError(static_cast< ReturnValue >(function_result));
+ }
+ }
+ else if(return_value != nullptr)
+ {
+ // caller wants return value
+ *return_value = static_cast< ReturnValue >(function_result);
+ }
+
+ return static_cast< ReturnValue >(function_result) == ReturnValue::OK;
+ }
+}
+
+void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin)
+ {
+ slot.initialize(label, so_pin);
+ set_pin(slot, so_pin, pin);
+ }
+
+void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::User, old_pin);
+ session.set_pin(old_pin, new_pin);
+ }
+
+void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::SO, old_so_pin);
+ session.set_pin(old_so_pin, new_so_pin);
+ }
+
+void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::SO, so_pin);
+ session.init_pin(pin);
+ }
+
+LowLevel::LowLevel(FunctionListPtr ptr) :
+ m_func_list_ptr(ptr)
+ {
+ if(m_func_list_ptr == nullptr)
+ {
+ throw Invalid_Argument("Invalid PKCS#11 function list ptr");
+ }
+ }
+
+LowLevel::~LowLevel() BOTAN_NOEXCEPT
+{}
+
+/****************************** General purpose functions ******************************/
+
+bool LowLevel::C_Initialize(VoidPtr init_args,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Initialize(init_args), return_value);
+ }
+
+bool LowLevel::C_Finalize(VoidPtr reserved,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Finalize(reserved), return_value);
+ }
+
+bool LowLevel::C_GetInfo(Info* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetInfo(info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr,
+ ReturnValue* return_value)
+ {
+ using get_function_list = CK_RV(*)(FunctionListPtr*);
+
+ get_function_list get_function_list_ptr = pkcs11_module.resolve<get_function_list>("C_GetFunctionList");
+
+ return handle_return_value(get_function_list_ptr(function_list_ptr_ptr), return_value);
+ }
+
+/****************************** Slot and token management functions ******************************/
+
+bool LowLevel::C_GetSlotList(Bbool token_present,
+ SlotId* slot_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSlotList(token_present, slot_list_ptr, count_ptr), return_value);
+ }
+
+bool LowLevel::C_GetSlotList(bool token_present,
+ std::vector<SlotId>& slot_ids,
+ ReturnValue* return_value) const
+ {
+ slot_ids.clear();
+
+ // first get available slots
+ Ulong number_slots = 0;
+
+ bool success = C_GetSlotList(token_present, nullptr, &number_slots, return_value);
+
+ if(!success || !number_slots)
+ {
+ return success;
+ }
+
+ // get actual slot ids
+ slot_ids.resize(number_slots);
+ return C_GetSlotList(token_present, slot_ids.data(), &number_slots, return_value);
+ }
+
+bool LowLevel::C_GetSlotInfo(SlotId slot_id,
+ SlotInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSlotInfo(slot_id, info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetTokenInfo(SlotId slot_id,
+ TokenInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetTokenInfo(slot_id, info_ptr), return_value);
+ }
+
+bool LowLevel::C_WaitForSlotEvent(Flags flags,
+ SlotId* slot_ptr,
+ VoidPtr reserved,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_WaitForSlotEvent(flags, slot_ptr, reserved), return_value);
+ }
+
+bool LowLevel::C_GetMechanismList(SlotId slot_id,
+ MechanismType* mechanism_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetMechanismList(slot_id,
+ reinterpret_cast< CK_MECHANISM_TYPE_PTR >(mechanism_list_ptr), count_ptr), return_value);
+ }
+
+bool LowLevel::C_GetMechanismList(SlotId slot_id,
+ std::vector<MechanismType>& mechanisms,
+ ReturnValue* return_value) const
+ {
+ mechanisms.clear();
+
+ // first get number of mechanisms
+ Ulong number_mechanisms = 0;
+
+ bool success = C_GetMechanismList(slot_id, nullptr, &number_mechanisms, return_value);
+
+ if(!success || !number_mechanisms)
+ {
+ return success;
+ }
+
+ // get actual mechanisms
+ mechanisms.resize(number_mechanisms);
+ return C_GetMechanismList(slot_id, reinterpret_cast< MechanismType* >(mechanisms.data()), &number_mechanisms,
+ return_value);
+ }
+
+bool LowLevel::C_GetMechanismInfo(SlotId slot_id,
+ MechanismType type,
+ MechanismInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetMechanismInfo(slot_id, static_cast< CK_MECHANISM_TYPE >(type),
+ info_ptr), return_value);
+ }
+
+bool LowLevel::C_InitToken(SlotId slot_id,
+ Utf8Char* so_pin_ptr,
+ Ulong so_pin_len,
+ Utf8Char* label_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_InitToken(slot_id, so_pin_ptr, so_pin_len, label_ptr), return_value);
+ }
+
+bool LowLevel::C_InitPIN(SessionHandle session,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_InitPIN(session, pin_ptr, pin_len), return_value);
+ }
+
+bool LowLevel::C_SetPIN(SessionHandle session,
+ Utf8Char* old_pin_ptr,
+ Ulong old_len,
+ Utf8Char* new_pin_ptr,
+ Ulong new_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetPIN(session, old_pin_ptr, old_len, new_pin_ptr, new_len),
+ return_value);
+ }
+
+/****************************** Session management ******************************/
+
+bool LowLevel::C_OpenSession(SlotId slot_id,
+ Flags flags,
+ VoidPtr application,
+ Notify notify,
+ SessionHandle* session_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_OpenSession(slot_id, flags, application, notify, session_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_CloseSession(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CloseSession(session), return_value);
+ }
+
+bool LowLevel::C_CloseAllSessions(SlotId slot_id,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CloseAllSessions(slot_id), return_value);
+ }
+
+bool LowLevel::C_GetSessionInfo(SessionHandle session,
+ SessionInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSessionInfo(session, info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong* operation_state_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetOperationState(session, operation_state_ptr, operation_state_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_SetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong operation_state_len,
+ ObjectHandle encryption_key,
+ ObjectHandle authentication_key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetOperationState(session, operation_state_ptr, operation_state_len,
+ encryption_key, authentication_key), return_value);
+ }
+
+bool LowLevel::C_Login(SessionHandle session,
+ UserType user_type,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Login(session, static_cast< CK_USER_TYPE >(user_type), pin_ptr, pin_len),
+ return_value);
+ }
+
+bool LowLevel::C_Logout(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Logout(session), return_value);
+ }
+
+/****************************** Object management functions ******************************/
+
+bool LowLevel::C_CreateObject(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* object_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CreateObject(session, attribute_template_ptr, count, object_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_CopyObject(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* new_object_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CopyObject(session, object, attribute_template_ptr, count,
+ new_object_ptr), return_value);
+ }
+
+bool LowLevel::C_DestroyObject(SessionHandle session,
+ ObjectHandle object,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DestroyObject(session, object), return_value);
+ }
+
+bool LowLevel::C_GetObjectSize(SessionHandle session,
+ ObjectHandle object,
+ Ulong* size_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetObjectSize(session, object, size_ptr), return_value);
+ }
+
+bool LowLevel::C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetAttributeValue(session, object, attribute_template_ptr, count),
+ return_value);
+ }
+
+bool LowLevel::C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetAttributeValue(session, object, attribute_template_ptr, count),
+ return_value);
+ }
+
+bool LowLevel::C_FindObjectsInit(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjectsInit(session, attribute_template_ptr, count), return_value);
+ }
+
+bool LowLevel::C_FindObjects(SessionHandle session,
+ ObjectHandle* object_ptr,
+ Ulong max_object_count,
+ Ulong* object_count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjects(session, object_ptr, max_object_count, object_count_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_FindObjectsFinal(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjectsFinal(session), return_value);
+ }
+
+/****************************** Encryption functions ******************************/
+
+bool LowLevel::C_EncryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Encrypt(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* encrypted_data_ptr,
+ Ulong* encrypted_data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Encrypt(session, data_ptr, data_len, encrypted_data_ptr,
+ encrypted_data_len_ptr), return_value);
+ }
+
+bool LowLevel::C_EncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_EncryptFinal(SessionHandle session,
+ Byte* last_encrypted_part_ptr,
+ Ulong* last_encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptFinal(session, last_encrypted_part_ptr,
+ last_encrypted_part_len_ptr), return_value);
+ }
+
+/****************************** Decryption functions ******************************/
+
+bool LowLevel::C_DecryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Decrypt(SessionHandle session,
+ Byte* encrypted_data_ptr,
+ Ulong encrypted_data_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Decrypt(session, encrypted_data_ptr, encrypted_data_len, data_ptr,
+ data_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr,
+ part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptFinal(SessionHandle session,
+ Byte* last_part_ptr,
+ Ulong* last_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptFinal(session, last_part_ptr, last_part_len_ptr), return_value);
+ }
+
+/****************************** Message digesting functions ******************************/
+
+bool LowLevel::C_DigestInit(SessionHandle session,
+ Mechanism* mechanism,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestInit(session, mechanism), return_value);
+ }
+
+bool LowLevel::C_Digest(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Digest(session, data_ptr, data_len, digest_ptr, digest_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_DigestUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_DigestKey(SessionHandle session,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestKey(session, key), return_value);
+ }
+
+bool LowLevel::C_DigestFinal(SessionHandle session,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestFinal(session, digest_ptr, digest_len_ptr), return_value);
+ }
+
+/****************************** Signing and MACing functions ******************************/
+
+bool LowLevel::C_SignInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Sign(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Sign(session, data_ptr, data_len, signature_ptr, signature_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_SignUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_SignFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignFinal(session, signature_ptr, signature_len_ptr), return_value);
+ }
+
+bool LowLevel::C_SignRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignRecoverInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_SignRecover(SessionHandle session,
+ Byte* data,
+ Ulong data_len,
+ Byte* signature,
+ Ulong* signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignRecover(session, data, data_len, signature, signature_len),
+ return_value);
+ }
+
+/****************************** Functions for verifying signatures and MACs ******************************/
+
+bool LowLevel::C_VerifyInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Verify(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Verify(session, data_ptr, data_len, signature_ptr, signature_len),
+ return_value);
+ }
+
+bool LowLevel::C_VerifyUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_VerifyFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyFinal(session, signature_ptr, signature_len), return_value);
+ }
+
+bool LowLevel::C_VerifyRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyRecoverInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_VerifyRecover(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyRecover(session, signature_ptr, signature_len, data_ptr,
+ data_len_ptr), return_value);
+ }
+
+/****************************** Dual-purpose cryptographic functions ******************************/
+
+bool LowLevel::C_DigestEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptDigestUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptDigestUpdate(session, encrypted_part_ptr, encrypted_part_len,
+ part_ptr, part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_SignEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptVerifyUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptVerifyUpdate(session, encrypted_part_ptr, encrypted_part_len,
+ part_ptr, part_len_ptr), return_value);
+ }
+
+/****************************** Key management functions ******************************/
+
+bool LowLevel::C_GenerateKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateKey(session, mechanism_ptr, attribute_template_ptr, count,
+ key_ptr), return_value);
+ }
+
+bool LowLevel::C_GenerateKeyPair(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* public_key_template_ptr,
+ Ulong public_key_attribute_count,
+ Attribute* private_key_template_ptr,
+ Ulong private_key_attribute_count,
+ ObjectHandle* public_key_ptr,
+ ObjectHandle* private_key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateKeyPair(session, mechanism_ptr, public_key_template_ptr,
+ public_key_attribute_count, private_key_template_ptr,
+ private_key_attribute_count, public_key_ptr, private_key_ptr), return_value);
+ }
+
+bool LowLevel::C_WrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle wrapping_key,
+ ObjectHandle key,
+ Byte* wrapped_key_ptr,
+ Ulong* wrapped_key_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_WrapKey(session, mechanism_ptr, wrapping_key, key, wrapped_key_ptr,
+ wrapped_key_len_ptr), return_value);
+ }
+
+bool LowLevel::C_UnwrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle unwrapping_key,
+ Byte* wrapped_key_ptr,
+ Ulong wrapped_key_len,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_UnwrapKey(session, mechanism_ptr, unwrapping_key, wrapped_key_ptr,
+ wrapped_key_len, attribute_template_ptr,
+ attribute_count, key_ptr), return_value);
+ }
+
+bool LowLevel::C_DeriveKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle base_key,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DeriveKey(session, mechanism_ptr, base_key, attribute_template_ptr,
+ attribute_count, key_ptr), return_value);
+ }
+
+/****************************** Random number generation functions ******************************/
+
+bool LowLevel::C_SeedRandom(SessionHandle session,
+ Byte* seed_ptr,
+ Ulong seed_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SeedRandom(session, seed_ptr, seed_len), return_value);
+ }
+
+bool LowLevel::C_GenerateRandom(SessionHandle session,
+ Byte* random_data_ptr,
+ Ulong random_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateRandom(session, random_data_ptr, random_len), return_value);
+ }
+
+/****************************** Parallel function management functions ******************************/
+
+bool LowLevel::C_GetFunctionStatus(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetFunctionStatus(session), return_value);
+ }
+
+bool LowLevel::C_CancelFunction(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CancelFunction(session), return_value);
+ }
+
+}
+
+}
diff --git a/src/lib/prov/pkcs11/p11.h b/src/lib/prov/pkcs11/p11.h
new file mode 100644
index 000000000..c18c07d59
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11.h
@@ -0,0 +1,2861 @@
+/*
+* PKCS#11
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_H__
+#define BOTAN_P11_H__
+
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <botan/dyn_load.h>
+
+#include <vector>
+#include <string>
+#include <map>
+
+#define BOTAN_PKCS11_RSA_PRIO 90
+#define BOTAN_PKCS11_ECDSA_PRIO 90
+#define BOTAN_PKCS11_ECDH_PRIO 90
+
+#define CK_PTR *
+
+#if defined(_MSC_VER)
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType __declspec(dllimport) name
+#else
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+#endif
+
+#if defined(_MSC_VER)
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType __declspec(dllimport) (* name)
+#else
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+#endif
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+#ifndef NULL_PTR
+ #define NULL_PTR nullptr
+#endif
+
+#if defined(_MSC_VER)
+ #pragma pack(push, cryptoki, 1)
+#endif
+
+#include "pkcs11.h"
+
+#if defined(_MSC_VER)
+ #pragma pack(pop, cryptoki)
+#endif
+
+static_assert(CRYPTOKI_VERSION_MAJOR == 2 && CRYPTOKI_VERSION_MINOR == 40,
+ "The Botan PKCS#11 module was implemented against PKCS#11 v2.40. Please use the correct PKCS#11 headers.");
+
+namespace Botan {
+namespace PKCS11 {
+
+using secure_string = secure_vector<byte>;
+
+enum class AttributeType : CK_ATTRIBUTE_TYPE
+ {
+ Class = CKA_CLASS,
+ Token = CKA_TOKEN,
+ Private = CKA_PRIVATE,
+ Label = CKA_LABEL,
+ Application = CKA_APPLICATION,
+ Value = CKA_VALUE,
+ ObjectId = CKA_OBJECT_ID,
+ CertificateType = CKA_CERTIFICATE_TYPE,
+ Issuer = CKA_ISSUER,
+ SerialNumber = CKA_SERIAL_NUMBER,
+ AcIssuer = CKA_AC_ISSUER,
+ Owner = CKA_OWNER,
+ AttrTypes = CKA_ATTR_TYPES,
+ Trusted = CKA_TRUSTED,
+ CertificateCategory = CKA_CERTIFICATE_CATEGORY,
+ JavaMidpSecurityDomain = CKA_JAVA_MIDP_SECURITY_DOMAIN,
+ Url = CKA_URL,
+ HashOfSubjectPublicKey = CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
+ HashOfIssuerPublicKey = CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+ NameHashAlgorithm = CKA_NAME_HASH_ALGORITHM,
+ CheckValue = CKA_CHECK_VALUE,
+ KeyType = CKA_KEY_TYPE,
+ Subject = CKA_SUBJECT,
+ Id = CKA_ID,
+ Sensitive = CKA_SENSITIVE,
+ Encrypt = CKA_ENCRYPT,
+ Decrypt = CKA_DECRYPT,
+ Wrap = CKA_WRAP,
+ Unwrap = CKA_UNWRAP,
+ Sign = CKA_SIGN,
+ SignRecover = CKA_SIGN_RECOVER,
+ Verify = CKA_VERIFY,
+ VerifyRecover = CKA_VERIFY_RECOVER,
+ Derive = CKA_DERIVE,
+ StartDate = CKA_START_DATE,
+ EndDate = CKA_END_DATE,
+ Modulus = CKA_MODULUS,
+ ModulusBits = CKA_MODULUS_BITS,
+ PublicExponent = CKA_PUBLIC_EXPONENT,
+ PrivateExponent = CKA_PRIVATE_EXPONENT,
+ Prime1 = CKA_PRIME_1,
+ Prime2 = CKA_PRIME_2,
+ Exponent1 = CKA_EXPONENT_1,
+ Exponent2 = CKA_EXPONENT_2,
+ Coefficient = CKA_COEFFICIENT,
+ PublicKeyInfo = CKA_PUBLIC_KEY_INFO,
+ Prime = CKA_PRIME,
+ Subprime = CKA_SUBPRIME,
+ Base = CKA_BASE,
+ PrimeBits = CKA_PRIME_BITS,
+ SubprimeBits = CKA_SUBPRIME_BITS,
+ SubPrimeBits = CKA_SUB_PRIME_BITS,
+ ValueBits = CKA_VALUE_BITS,
+ ValueLen = CKA_VALUE_LEN,
+ Extractable = CKA_EXTRACTABLE,
+ Local = CKA_LOCAL,
+ NeverExtractable = CKA_NEVER_EXTRACTABLE,
+ AlwaysSensitive = CKA_ALWAYS_SENSITIVE,
+ KeyGenMechanism = CKA_KEY_GEN_MECHANISM,
+ Modifiable = CKA_MODIFIABLE,
+ Copyable = CKA_COPYABLE,
+ Destroyable = CKA_DESTROYABLE,
+ EcdsaParams = CKA_ECDSA_PARAMS,
+ EcParams = CKA_EC_PARAMS,
+ EcPoint = CKA_EC_POINT,
+ SecondaryAuth = CKA_SECONDARY_AUTH,
+ AuthPinFlags = CKA_AUTH_PIN_FLAGS,
+ AlwaysAuthenticate = CKA_ALWAYS_AUTHENTICATE,
+ WrapWithTrusted = CKA_WRAP_WITH_TRUSTED,
+ WrapTemplate = CKA_WRAP_TEMPLATE,
+ UnwrapTemplate = CKA_UNWRAP_TEMPLATE,
+ DeriveTemplate = CKA_DERIVE_TEMPLATE,
+ OtpFormat = CKA_OTP_FORMAT,
+ OtpLength = CKA_OTP_LENGTH,
+ OtpTimeInterval = CKA_OTP_TIME_INTERVAL,
+ OtpUserFriendlyMode = CKA_OTP_USER_FRIENDLY_MODE,
+ OtpChallengeRequirement = CKA_OTP_CHALLENGE_REQUIREMENT,
+ OtpTimeRequirement = CKA_OTP_TIME_REQUIREMENT,
+ OtpCounterRequirement = CKA_OTP_COUNTER_REQUIREMENT,
+ OtpPinRequirement = CKA_OTP_PIN_REQUIREMENT,
+ OtpCounter = CKA_OTP_COUNTER,
+ OtpTime = CKA_OTP_TIME,
+ OtpUserIdentifier = CKA_OTP_USER_IDENTIFIER,
+ OtpServiceIdentifier = CKA_OTP_SERVICE_IDENTIFIER,
+ OtpServiceLogo = CKA_OTP_SERVICE_LOGO,
+ OtpServiceLogoType = CKA_OTP_SERVICE_LOGO_TYPE,
+ Gostr3410Params = CKA_GOSTR3410_PARAMS,
+ Gostr3411Params = CKA_GOSTR3411_PARAMS,
+ Gost28147Params = CKA_GOST28147_PARAMS,
+ HwFeatureType = CKA_HW_FEATURE_TYPE,
+ ResetOnInit = CKA_RESET_ON_INIT,
+ HasReset = CKA_HAS_RESET,
+ PixelX = CKA_PIXEL_X,
+ PixelY = CKA_PIXEL_Y,
+ Resolution = CKA_RESOLUTION,
+ CharRows = CKA_CHAR_ROWS,
+ CharColumns = CKA_CHAR_COLUMNS,
+ Color = CKA_COLOR,
+ BitsPerPixel = CKA_BITS_PER_PIXEL,
+ CharSets = CKA_CHAR_SETS,
+ EncodingMethods = CKA_ENCODING_METHODS,
+ MimeTypes = CKA_MIME_TYPES,
+ MechanismType = CKA_MECHANISM_TYPE,
+ RequiredCmsAttributes = CKA_REQUIRED_CMS_ATTRIBUTES,
+ DefaultCmsAttributes = CKA_DEFAULT_CMS_ATTRIBUTES,
+ SupportedCmsAttributes = CKA_SUPPORTED_CMS_ATTRIBUTES,
+ AllowedMechanisms = CKA_ALLOWED_MECHANISMS,
+ VendorDefined = CKA_VENDOR_DEFINED,
+ };
+
+enum class CertificateType : CK_CERTIFICATE_TYPE
+ {
+ X509 = CKC_X_509,
+ X509AttrCert = CKC_X_509_ATTR_CERT,
+ Wtls = CKC_WTLS,
+ VendorDefined = CKC_VENDOR_DEFINED,
+ };
+
+/// Indicates if a stored certificate is a user certificate for which the corresponding private key is available
+/// on the token ("token user"), a CA certificate ("authority"), or another end-entity certificate ("other entity").
+enum class CertificateCategory : CK_ULONG
+ {
+ Unspecified = CK_CERTIFICATE_CATEGORY_UNSPECIFIED,
+ TokenUser = CK_CERTIFICATE_CATEGORY_TOKEN_USER,
+ Authority = CK_CERTIFICATE_CATEGORY_AUTHORITY,
+ OtherEntity = CK_CERTIFICATE_CATEGORY_OTHER_ENTITY
+ };
+
+enum class KeyDerivation : CK_ULONG
+ {
+ Null = CKD_NULL,
+ Sha1Kdf = CKD_SHA1_KDF,
+ Sha1KdfAsn1 = CKD_SHA1_KDF_ASN1,
+ Sha1KdfConcatenate = CKD_SHA1_KDF_CONCATENATE,
+ Sha224Kdf = CKD_SHA224_KDF,
+ Sha256Kdf = CKD_SHA256_KDF,
+ Sha384Kdf = CKD_SHA384_KDF,
+ Sha512Kdf = CKD_SHA512_KDF,
+ CpdiversifyKdf = CKD_CPDIVERSIFY_KDF,
+ };
+
+enum class Flag : CK_FLAGS
+ {
+ None = 0,
+ TokenPresent = CKF_TOKEN_PRESENT,
+ RemovableDevice = CKF_REMOVABLE_DEVICE,
+ HwSlot = CKF_HW_SLOT,
+ Rng = CKF_RNG,
+ WriteProtected = CKF_WRITE_PROTECTED,
+ LoginRequired = CKF_LOGIN_REQUIRED,
+ UserPinInitialized = CKF_USER_PIN_INITIALIZED,
+ RestoreKeyNotNeeded = CKF_RESTORE_KEY_NOT_NEEDED,
+ ClockOnToken = CKF_CLOCK_ON_TOKEN,
+ ProtectedAuthenticationPath = CKF_PROTECTED_AUTHENTICATION_PATH,
+ DualCryptoOperations = CKF_DUAL_CRYPTO_OPERATIONS,
+ TokenInitialized = CKF_TOKEN_INITIALIZED,
+ SecondaryAuthentication = CKF_SECONDARY_AUTHENTICATION,
+ UserPinCountLow = CKF_USER_PIN_COUNT_LOW,
+ UserPinFinalTry = CKF_USER_PIN_FINAL_TRY,
+ UserPinLocked = CKF_USER_PIN_LOCKED,
+ UserPinToBeChanged = CKF_USER_PIN_TO_BE_CHANGED,
+ SoPinCountLow = CKF_SO_PIN_COUNT_LOW,
+ SoPinFinalTry = CKF_SO_PIN_FINAL_TRY,
+ SoPinLocked = CKF_SO_PIN_LOCKED,
+ SoPinToBeChanged = CKF_SO_PIN_TO_BE_CHANGED,
+ ErrorState = CKF_ERROR_STATE,
+ RwSession = CKF_RW_SESSION,
+ SerialSession = CKF_SERIAL_SESSION,
+ ArrayAttribute = CKF_ARRAY_ATTRIBUTE,
+ Hw = CKF_HW,
+ Encrypt = CKF_ENCRYPT,
+ Decrypt = CKF_DECRYPT,
+ Digest = CKF_DIGEST,
+ Sign = CKF_SIGN,
+ SignRecover = CKF_SIGN_RECOVER,
+ Verify = CKF_VERIFY,
+ VerifyRecover = CKF_VERIFY_RECOVER,
+ Generate = CKF_GENERATE,
+ GenerateKeyPair = CKF_GENERATE_KEY_PAIR,
+ Wrap = CKF_WRAP,
+ Unwrap = CKF_UNWRAP,
+ Derive = CKF_DERIVE,
+ EcFP = CKF_EC_F_P,
+ EcF2m = CKF_EC_F_2M,
+ EcEcparameters = CKF_EC_ECPARAMETERS,
+ EcNamedcurve = CKF_EC_NAMEDCURVE,
+ EcUncompress = CKF_EC_UNCOMPRESS,
+ EcCompress = CKF_EC_COMPRESS,
+ Extension = CKF_EXTENSION,
+ LibraryCantCreateOsThreads = CKF_LIBRARY_CANT_CREATE_OS_THREADS,
+ OsLockingOk = CKF_OS_LOCKING_OK,
+ DontBlock = CKF_DONT_BLOCK,
+ NextOtp = CKF_NEXT_OTP,
+ ExcludeTime = CKF_EXCLUDE_TIME,
+ ExcludeCounter = CKF_EXCLUDE_COUNTER,
+ ExcludeChallenge = CKF_EXCLUDE_CHALLENGE,
+ ExcludePin = CKF_EXCLUDE_PIN,
+ UserFriendlyOtp = CKF_USER_FRIENDLY_OTP,
+ };
+
+inline Flag operator | (Flag a, Flag b)
+ {
+ return static_cast< Flag >(static_cast< CK_FLAGS >(a) | static_cast< CK_FLAGS >(b));
+ }
+
+enum class MGF : CK_RSA_PKCS_MGF_TYPE
+ {
+ Mgf1Sha1 = CKG_MGF1_SHA1,
+ Mgf1Sha256 = CKG_MGF1_SHA256,
+ Mgf1Sha384 = CKG_MGF1_SHA384,
+ Mgf1Sha512 = CKG_MGF1_SHA512,
+ Mgf1Sha224 = CKG_MGF1_SHA224,
+ };
+
+enum class HardwareType : CK_HW_FEATURE_TYPE
+ {
+ MonotonicCounter = CKH_MONOTONIC_COUNTER,
+ Clock = CKH_CLOCK,
+ UserInterface = CKH_USER_INTERFACE,
+ VendorDefined = CKH_VENDOR_DEFINED,
+ };
+
+enum class KeyType : CK_KEY_TYPE
+ {
+ Rsa = CKK_RSA,
+ Dsa = CKK_DSA,
+ Dh = CKK_DH,
+ Ecdsa = CKK_ECDSA,
+ Ec = CKK_EC,
+ X942Dh = CKK_X9_42_DH,
+ Kea = CKK_KEA,
+ GenericSecret = CKK_GENERIC_SECRET,
+ Rc2 = CKK_RC2,
+ Rc4 = CKK_RC4,
+ Des = CKK_DES,
+ Des2 = CKK_DES2,
+ Des3 = CKK_DES3,
+ Cast = CKK_CAST,
+ Cast3 = CKK_CAST3,
+ Cast5 = CKK_CAST5,
+ Cast128 = CKK_CAST128,
+ Rc5 = CKK_RC5,
+ Idea = CKK_IDEA,
+ Skipjack = CKK_SKIPJACK,
+ Baton = CKK_BATON,
+ Juniper = CKK_JUNIPER,
+ Cdmf = CKK_CDMF,
+ Aes = CKK_AES,
+ Blowfish = CKK_BLOWFISH,
+ Twofish = CKK_TWOFISH,
+ Securid = CKK_SECURID,
+ Hotp = CKK_HOTP,
+ Acti = CKK_ACTI,
+ Camellia = CKK_CAMELLIA,
+ Aria = CKK_ARIA,
+ Md5Hmac = CKK_MD5_HMAC,
+ Sha1Hmac = CKK_SHA_1_HMAC,
+ Ripemd128Hmac = CKK_RIPEMD128_HMAC,
+ Ripemd160Hmac = CKK_RIPEMD160_HMAC,
+ Sha256Hmac = CKK_SHA256_HMAC,
+ Sha384Hmac = CKK_SHA384_HMAC,
+ Sha512Hmac = CKK_SHA512_HMAC,
+ Sha224Hmac = CKK_SHA224_HMAC,
+ Seed = CKK_SEED,
+ Gostr3410 = CKK_GOSTR3410,
+ Gostr3411 = CKK_GOSTR3411,
+ Gost28147 = CKK_GOST28147,
+ VendorDefined = CKK_VENDOR_DEFINED,
+ };
+
+enum class MechanismType : CK_MECHANISM_TYPE
+ {
+ RsaPkcsKeyPairGen = CKM_RSA_PKCS_KEY_PAIR_GEN,
+ RsaPkcs = CKM_RSA_PKCS,
+ Rsa9796 = CKM_RSA_9796,
+ RsaX509 = CKM_RSA_X_509,
+ Md2RsaPkcs = CKM_MD2_RSA_PKCS,
+ Md5RsaPkcs = CKM_MD5_RSA_PKCS,
+ Sha1RsaPkcs = CKM_SHA1_RSA_PKCS,
+ Ripemd128RsaPkcs = CKM_RIPEMD128_RSA_PKCS,
+ Ripemd160RsaPkcs = CKM_RIPEMD160_RSA_PKCS,
+ RsaPkcsOaep = CKM_RSA_PKCS_OAEP,
+ RsaX931KeyPairGen = CKM_RSA_X9_31_KEY_PAIR_GEN,
+ RsaX931 = CKM_RSA_X9_31,
+ Sha1RsaX931 = CKM_SHA1_RSA_X9_31,
+ RsaPkcsPss = CKM_RSA_PKCS_PSS,
+ Sha1RsaPkcsPss = CKM_SHA1_RSA_PKCS_PSS,
+ DsaKeyPairGen = CKM_DSA_KEY_PAIR_GEN,
+ Dsa = CKM_DSA,
+ DsaSha1 = CKM_DSA_SHA1,
+ DsaSha224 = CKM_DSA_SHA224,
+ DsaSha256 = CKM_DSA_SHA256,
+ DsaSha384 = CKM_DSA_SHA384,
+ DsaSha512 = CKM_DSA_SHA512,
+ DhPkcsKeyPairGen = CKM_DH_PKCS_KEY_PAIR_GEN,
+ DhPkcsDerive = CKM_DH_PKCS_DERIVE,
+ X942DhKeyPairGen = CKM_X9_42_DH_KEY_PAIR_GEN,
+ X942DhDerive = CKM_X9_42_DH_DERIVE,
+ X942DhHybridDerive = CKM_X9_42_DH_HYBRID_DERIVE,
+ X942MqvDerive = CKM_X9_42_MQV_DERIVE,
+ Sha256RsaPkcs = CKM_SHA256_RSA_PKCS,
+ Sha384RsaPkcs = CKM_SHA384_RSA_PKCS,
+ Sha512RsaPkcs = CKM_SHA512_RSA_PKCS,
+ Sha256RsaPkcsPss = CKM_SHA256_RSA_PKCS_PSS,
+ Sha384RsaPkcsPss = CKM_SHA384_RSA_PKCS_PSS,
+ Sha512RsaPkcsPss = CKM_SHA512_RSA_PKCS_PSS,
+ Sha224RsaPkcs = CKM_SHA224_RSA_PKCS,
+ Sha224RsaPkcsPss = CKM_SHA224_RSA_PKCS_PSS,
+ Sha512224 = CKM_SHA512_224,
+ Sha512224Hmac = CKM_SHA512_224_HMAC,
+ Sha512224HmacGeneral = CKM_SHA512_224_HMAC_GENERAL,
+ Sha512224KeyDerivation = CKM_SHA512_224_KEY_DERIVATION,
+ Sha512256 = CKM_SHA512_256,
+ Sha512256Hmac = CKM_SHA512_256_HMAC,
+ Sha512256HmacGeneral = CKM_SHA512_256_HMAC_GENERAL,
+ Sha512256KeyDerivation = CKM_SHA512_256_KEY_DERIVATION,
+ Sha512T = CKM_SHA512_T,
+ Sha512THmac = CKM_SHA512_T_HMAC,
+ Sha512THmacGeneral = CKM_SHA512_T_HMAC_GENERAL,
+ Sha512TKeyDerivation = CKM_SHA512_T_KEY_DERIVATION,
+ Rc2KeyGen = CKM_RC2_KEY_GEN,
+ Rc2Ecb = CKM_RC2_ECB,
+ Rc2Cbc = CKM_RC2_CBC,
+ Rc2Mac = CKM_RC2_MAC,
+ Rc2MacGeneral = CKM_RC2_MAC_GENERAL,
+ Rc2CbcPad = CKM_RC2_CBC_PAD,
+ Rc4KeyGen = CKM_RC4_KEY_GEN,
+ Rc4 = CKM_RC4,
+ DesKeyGen = CKM_DES_KEY_GEN,
+ DesEcb = CKM_DES_ECB,
+ DesCbc = CKM_DES_CBC,
+ DesMac = CKM_DES_MAC,
+ DesMacGeneral = CKM_DES_MAC_GENERAL,
+ DesCbcPad = CKM_DES_CBC_PAD,
+ Des2KeyGen = CKM_DES2_KEY_GEN,
+ Des3KeyGen = CKM_DES3_KEY_GEN,
+ Des3Ecb = CKM_DES3_ECB,
+ Des3Cbc = CKM_DES3_CBC,
+ Des3Mac = CKM_DES3_MAC,
+ Des3MacGeneral = CKM_DES3_MAC_GENERAL,
+ Des3CbcPad = CKM_DES3_CBC_PAD,
+ Des3CmacGeneral = CKM_DES3_CMAC_GENERAL,
+ Des3Cmac = CKM_DES3_CMAC,
+ CdmfKeyGen = CKM_CDMF_KEY_GEN,
+ CdmfEcb = CKM_CDMF_ECB,
+ CdmfCbc = CKM_CDMF_CBC,
+ CdmfMac = CKM_CDMF_MAC,
+ CdmfMacGeneral = CKM_CDMF_MAC_GENERAL,
+ CdmfCbcPad = CKM_CDMF_CBC_PAD,
+ DesOfb64 = CKM_DES_OFB64,
+ DesOfb8 = CKM_DES_OFB8,
+ DesCfb64 = CKM_DES_CFB64,
+ DesCfb8 = CKM_DES_CFB8,
+ Md2 = CKM_MD2,
+ Md2Hmac = CKM_MD2_HMAC,
+ Md2HmacGeneral = CKM_MD2_HMAC_GENERAL,
+ Md5 = CKM_MD5,
+ Md5Hmac = CKM_MD5_HMAC,
+ Md5HmacGeneral = CKM_MD5_HMAC_GENERAL,
+ Sha1 = CKM_SHA_1,
+ Sha1Hmac = CKM_SHA_1_HMAC,
+ Sha1HmacGeneral = CKM_SHA_1_HMAC_GENERAL,
+ Ripemd128 = CKM_RIPEMD128,
+ Ripemd128Hmac = CKM_RIPEMD128_HMAC,
+ Ripemd128HmacGeneral = CKM_RIPEMD128_HMAC_GENERAL,
+ Ripemd160 = CKM_RIPEMD160,
+ Ripemd160Hmac = CKM_RIPEMD160_HMAC,
+ Ripemd160HmacGeneral = CKM_RIPEMD160_HMAC_GENERAL,
+ Sha256 = CKM_SHA256,
+ Sha256Hmac = CKM_SHA256_HMAC,
+ Sha256HmacGeneral = CKM_SHA256_HMAC_GENERAL,
+ Sha224 = CKM_SHA224,
+ Sha224Hmac = CKM_SHA224_HMAC,
+ Sha224HmacGeneral = CKM_SHA224_HMAC_GENERAL,
+ Sha384 = CKM_SHA384,
+ Sha384Hmac = CKM_SHA384_HMAC,
+ Sha384HmacGeneral = CKM_SHA384_HMAC_GENERAL,
+ Sha512 = CKM_SHA512,
+ Sha512Hmac = CKM_SHA512_HMAC,
+ Sha512HmacGeneral = CKM_SHA512_HMAC_GENERAL,
+ SecuridKeyGen = CKM_SECURID_KEY_GEN,
+ Securid = CKM_SECURID,
+ HotpKeyGen = CKM_HOTP_KEY_GEN,
+ Hotp = CKM_HOTP,
+ Acti = CKM_ACTI,
+ ActiKeyGen = CKM_ACTI_KEY_GEN,
+ CastKeyGen = CKM_CAST_KEY_GEN,
+ CastEcb = CKM_CAST_ECB,
+ CastCbc = CKM_CAST_CBC,
+ CastMac = CKM_CAST_MAC,
+ CastMacGeneral = CKM_CAST_MAC_GENERAL,
+ CastCbcPad = CKM_CAST_CBC_PAD,
+ Cast3KeyGen = CKM_CAST3_KEY_GEN,
+ Cast3Ecb = CKM_CAST3_ECB,
+ Cast3Cbc = CKM_CAST3_CBC,
+ Cast3Mac = CKM_CAST3_MAC,
+ Cast3MacGeneral = CKM_CAST3_MAC_GENERAL,
+ Cast3CbcPad = CKM_CAST3_CBC_PAD,
+ Cast5KeyGen = CKM_CAST5_KEY_GEN,
+ Cast128KeyGen = CKM_CAST128_KEY_GEN,
+ Cast5Ecb = CKM_CAST5_ECB,
+ Cast128Ecb = CKM_CAST128_ECB,
+ Cast5Cbc = CKM_CAST5_CBC,
+ Cast128Cbc = CKM_CAST128_CBC,
+ Cast5Mac = CKM_CAST5_MAC,
+ Cast128Mac = CKM_CAST128_MAC,
+ Cast5MacGeneral = CKM_CAST5_MAC_GENERAL,
+ Cast128MacGeneral = CKM_CAST128_MAC_GENERAL,
+ Cast5CbcPad = CKM_CAST5_CBC_PAD,
+ Cast128CbcPad = CKM_CAST128_CBC_PAD,
+ Rc5KeyGen = CKM_RC5_KEY_GEN,
+ Rc5Ecb = CKM_RC5_ECB,
+ Rc5Cbc = CKM_RC5_CBC,
+ Rc5Mac = CKM_RC5_MAC,
+ Rc5MacGeneral = CKM_RC5_MAC_GENERAL,
+ Rc5CbcPad = CKM_RC5_CBC_PAD,
+ IdeaKeyGen = CKM_IDEA_KEY_GEN,
+ IdeaEcb = CKM_IDEA_ECB,
+ IdeaCbc = CKM_IDEA_CBC,
+ IdeaMac = CKM_IDEA_MAC,
+ IdeaMacGeneral = CKM_IDEA_MAC_GENERAL,
+ IdeaCbcPad = CKM_IDEA_CBC_PAD,
+ GenericSecretKeyGen = CKM_GENERIC_SECRET_KEY_GEN,
+ ConcatenateBaseAndKey = CKM_CONCATENATE_BASE_AND_KEY,
+ ConcatenateBaseAndData = CKM_CONCATENATE_BASE_AND_DATA,
+ ConcatenateDataAndBase = CKM_CONCATENATE_DATA_AND_BASE,
+ XorBaseAndData = CKM_XOR_BASE_AND_DATA,
+ ExtractKeyFromKey = CKM_EXTRACT_KEY_FROM_KEY,
+ Ssl3PreMasterKeyGen = CKM_SSL3_PRE_MASTER_KEY_GEN,
+ Ssl3MasterKeyDerive = CKM_SSL3_MASTER_KEY_DERIVE,
+ Ssl3KeyAndMacDerive = CKM_SSL3_KEY_AND_MAC_DERIVE,
+ Ssl3MasterKeyDeriveDh = CKM_SSL3_MASTER_KEY_DERIVE_DH,
+ TlsPreMasterKeyGen = CKM_TLS_PRE_MASTER_KEY_GEN,
+ TlsMasterKeyDerive = CKM_TLS_MASTER_KEY_DERIVE,
+ TlsKeyAndMacDerive = CKM_TLS_KEY_AND_MAC_DERIVE,
+ TlsMasterKeyDeriveDh = CKM_TLS_MASTER_KEY_DERIVE_DH,
+ TlsPrf = CKM_TLS_PRF,
+ Ssl3Md5Mac = CKM_SSL3_MD5_MAC,
+ Ssl3Sha1Mac = CKM_SSL3_SHA1_MAC,
+ Md5KeyDerivation = CKM_MD5_KEY_DERIVATION,
+ Md2KeyDerivation = CKM_MD2_KEY_DERIVATION,
+ Sha1KeyDerivation = CKM_SHA1_KEY_DERIVATION,
+ Sha256KeyDerivation = CKM_SHA256_KEY_DERIVATION,
+ Sha384KeyDerivation = CKM_SHA384_KEY_DERIVATION,
+ Sha512KeyDerivation = CKM_SHA512_KEY_DERIVATION,
+ Sha224KeyDerivation = CKM_SHA224_KEY_DERIVATION,
+ PbeMd2DesCbc = CKM_PBE_MD2_DES_CBC,
+ PbeMd5DesCbc = CKM_PBE_MD5_DES_CBC,
+ PbeMd5CastCbc = CKM_PBE_MD5_CAST_CBC,
+ PbeMd5Cast3Cbc = CKM_PBE_MD5_CAST3_CBC,
+ PbeMd5Cast5Cbc = CKM_PBE_MD5_CAST5_CBC,
+ PbeMd5Cast128Cbc = CKM_PBE_MD5_CAST128_CBC,
+ PbeSha1Cast5Cbc = CKM_PBE_SHA1_CAST5_CBC,
+ PbeSha1Cast128Cbc = CKM_PBE_SHA1_CAST128_CBC,
+ PbeSha1Rc4128 = CKM_PBE_SHA1_RC4_128,
+ PbeSha1Rc440 = CKM_PBE_SHA1_RC4_40,
+ PbeSha1Des3EdeCbc = CKM_PBE_SHA1_DES3_EDE_CBC,
+ PbeSha1Des2EdeCbc = CKM_PBE_SHA1_DES2_EDE_CBC,
+ PbeSha1Rc2128Cbc = CKM_PBE_SHA1_RC2_128_CBC,
+ PbeSha1Rc240Cbc = CKM_PBE_SHA1_RC2_40_CBC,
+ Pkcs5Pbkd2 = CKM_PKCS5_PBKD2,
+ PbaSha1WithSha1Hmac = CKM_PBA_SHA1_WITH_SHA1_HMAC,
+ WtlsPreMasterKeyGen = CKM_WTLS_PRE_MASTER_KEY_GEN,
+ WtlsMasterKeyDerive = CKM_WTLS_MASTER_KEY_DERIVE,
+ WtlsMasterKeyDeriveDhEcc = CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC,
+ WtlsPrf = CKM_WTLS_PRF,
+ WtlsServerKeyAndMacDerive = CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE,
+ WtlsClientKeyAndMacDerive = CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE,
+ Tls10MacServer = CKM_TLS10_MAC_SERVER,
+ Tls10MacClient = CKM_TLS10_MAC_CLIENT,
+ Tls12Mac = CKM_TLS12_MAC,
+ Tls12Kdf = CKM_TLS12_KDF,
+ Tls12MasterKeyDerive = CKM_TLS12_MASTER_KEY_DERIVE,
+ Tls12KeyAndMacDerive = CKM_TLS12_KEY_AND_MAC_DERIVE,
+ Tls12MasterKeyDeriveDh = CKM_TLS12_MASTER_KEY_DERIVE_DH,
+ Tls12KeySafeDerive = CKM_TLS12_KEY_SAFE_DERIVE,
+ TlsMac = CKM_TLS_MAC,
+ TlsKdf = CKM_TLS_KDF,
+ KeyWrapLynks = CKM_KEY_WRAP_LYNKS,
+ KeyWrapSetOaep = CKM_KEY_WRAP_SET_OAEP,
+ CmsSig = CKM_CMS_SIG,
+ KipDerive = CKM_KIP_DERIVE,
+ KipWrap = CKM_KIP_WRAP,
+ KipMac = CKM_KIP_MAC,
+ CamelliaKeyGen = CKM_CAMELLIA_KEY_GEN,
+ CamelliaEcb = CKM_CAMELLIA_ECB,
+ CamelliaCbc = CKM_CAMELLIA_CBC,
+ CamelliaMac = CKM_CAMELLIA_MAC,
+ CamelliaMacGeneral = CKM_CAMELLIA_MAC_GENERAL,
+ CamelliaCbcPad = CKM_CAMELLIA_CBC_PAD,
+ CamelliaEcbEncryptData = CKM_CAMELLIA_ECB_ENCRYPT_DATA,
+ CamelliaCbcEncryptData = CKM_CAMELLIA_CBC_ENCRYPT_DATA,
+ CamelliaCtr = CKM_CAMELLIA_CTR,
+ AriaKeyGen = CKM_ARIA_KEY_GEN,
+ AriaEcb = CKM_ARIA_ECB,
+ AriaCbc = CKM_ARIA_CBC,
+ AriaMac = CKM_ARIA_MAC,
+ AriaMacGeneral = CKM_ARIA_MAC_GENERAL,
+ AriaCbcPad = CKM_ARIA_CBC_PAD,
+ AriaEcbEncryptData = CKM_ARIA_ECB_ENCRYPT_DATA,
+ AriaCbcEncryptData = CKM_ARIA_CBC_ENCRYPT_DATA,
+ SeedKeyGen = CKM_SEED_KEY_GEN,
+ SeedEcb = CKM_SEED_ECB,
+ SeedCbc = CKM_SEED_CBC,
+ SeedMac = CKM_SEED_MAC,
+ SeedMacGeneral = CKM_SEED_MAC_GENERAL,
+ SeedCbcPad = CKM_SEED_CBC_PAD,
+ SeedEcbEncryptData = CKM_SEED_ECB_ENCRYPT_DATA,
+ SeedCbcEncryptData = CKM_SEED_CBC_ENCRYPT_DATA,
+ SkipjackKeyGen = CKM_SKIPJACK_KEY_GEN,
+ SkipjackEcb64 = CKM_SKIPJACK_ECB64,
+ SkipjackCbc64 = CKM_SKIPJACK_CBC64,
+ SkipjackOfb64 = CKM_SKIPJACK_OFB64,
+ SkipjackCfb64 = CKM_SKIPJACK_CFB64,
+ SkipjackCfb32 = CKM_SKIPJACK_CFB32,
+ SkipjackCfb16 = CKM_SKIPJACK_CFB16,
+ SkipjackCfb8 = CKM_SKIPJACK_CFB8,
+ SkipjackWrap = CKM_SKIPJACK_WRAP,
+ SkipjackPrivateWrap = CKM_SKIPJACK_PRIVATE_WRAP,
+ SkipjackRelayx = CKM_SKIPJACK_RELAYX,
+ KeaKeyPairGen = CKM_KEA_KEY_PAIR_GEN,
+ KeaKeyDerive = CKM_KEA_KEY_DERIVE,
+ KeaDerive = CKM_KEA_DERIVE,
+ FortezzaTimestamp = CKM_FORTEZZA_TIMESTAMP,
+ BatonKeyGen = CKM_BATON_KEY_GEN,
+ BatonEcb128 = CKM_BATON_ECB128,
+ BatonEcb96 = CKM_BATON_ECB96,
+ BatonCbc128 = CKM_BATON_CBC128,
+ BatonCounter = CKM_BATON_COUNTER,
+ BatonShuffle = CKM_BATON_SHUFFLE,
+ BatonWrap = CKM_BATON_WRAP,
+ EcdsaKeyPairGen = CKM_ECDSA_KEY_PAIR_GEN,
+ EcKeyPairGen = CKM_EC_KEY_PAIR_GEN,
+ Ecdsa = CKM_ECDSA,
+ EcdsaSha1 = CKM_ECDSA_SHA1,
+ EcdsaSha224 = CKM_ECDSA_SHA224,
+ EcdsaSha256 = CKM_ECDSA_SHA256,
+ EcdsaSha384 = CKM_ECDSA_SHA384,
+ EcdsaSha512 = CKM_ECDSA_SHA512,
+ Ecdh1Derive = CKM_ECDH1_DERIVE,
+ Ecdh1CofactorDerive = CKM_ECDH1_COFACTOR_DERIVE,
+ EcmqvDerive = CKM_ECMQV_DERIVE,
+ EcdhAesKeyWrap = CKM_ECDH_AES_KEY_WRAP,
+ RsaAesKeyWrap = CKM_RSA_AES_KEY_WRAP,
+ JuniperKeyGen = CKM_JUNIPER_KEY_GEN,
+ JuniperEcb128 = CKM_JUNIPER_ECB128,
+ JuniperCbc128 = CKM_JUNIPER_CBC128,
+ JuniperCounter = CKM_JUNIPER_COUNTER,
+ JuniperShuffle = CKM_JUNIPER_SHUFFLE,
+ JuniperWrap = CKM_JUNIPER_WRAP,
+ Fasthash = CKM_FASTHASH,
+ AesKeyGen = CKM_AES_KEY_GEN,
+ AesEcb = CKM_AES_ECB,
+ AesCbc = CKM_AES_CBC,
+ AesMac = CKM_AES_MAC,
+ AesMacGeneral = CKM_AES_MAC_GENERAL,
+ AesCbcPad = CKM_AES_CBC_PAD,
+ AesCtr = CKM_AES_CTR,
+ AesGcm = CKM_AES_GCM,
+ AesCcm = CKM_AES_CCM,
+ AesCts = CKM_AES_CTS,
+ AesCmac = CKM_AES_CMAC,
+ AesCmacGeneral = CKM_AES_CMAC_GENERAL,
+ AesXcbcMac = CKM_AES_XCBC_MAC,
+ AesXcbcMac96 = CKM_AES_XCBC_MAC_96,
+ AesGmac = CKM_AES_GMAC,
+ BlowfishKeyGen = CKM_BLOWFISH_KEY_GEN,
+ BlowfishCbc = CKM_BLOWFISH_CBC,
+ TwofishKeyGen = CKM_TWOFISH_KEY_GEN,
+ TwofishCbc = CKM_TWOFISH_CBC,
+ BlowfishCbcPad = CKM_BLOWFISH_CBC_PAD,
+ TwofishCbcPad = CKM_TWOFISH_CBC_PAD,
+ DesEcbEncryptData = CKM_DES_ECB_ENCRYPT_DATA,
+ DesCbcEncryptData = CKM_DES_CBC_ENCRYPT_DATA,
+ Des3EcbEncryptData = CKM_DES3_ECB_ENCRYPT_DATA,
+ Des3CbcEncryptData = CKM_DES3_CBC_ENCRYPT_DATA,
+ AesEcbEncryptData = CKM_AES_ECB_ENCRYPT_DATA,
+ AesCbcEncryptData = CKM_AES_CBC_ENCRYPT_DATA,
+ Gostr3410KeyPairGen = CKM_GOSTR3410_KEY_PAIR_GEN,
+ Gostr3410 = CKM_GOSTR3410,
+ Gostr3410WithGostr3411 = CKM_GOSTR3410_WITH_GOSTR3411,
+ Gostr3410KeyWrap = CKM_GOSTR3410_KEY_WRAP,
+ Gostr3410Derive = CKM_GOSTR3410_DERIVE,
+ Gostr3411 = CKM_GOSTR3411,
+ Gostr3411Hmac = CKM_GOSTR3411_HMAC,
+ Gost28147KeyGen = CKM_GOST28147_KEY_GEN,
+ Gost28147Ecb = CKM_GOST28147_ECB,
+ Gost28147 = CKM_GOST28147,
+ Gost28147Mac = CKM_GOST28147_MAC,
+ Gost28147KeyWrap = CKM_GOST28147_KEY_WRAP,
+ DsaParameterGen = CKM_DSA_PARAMETER_GEN,
+ DhPkcsParameterGen = CKM_DH_PKCS_PARAMETER_GEN,
+ X942DhParameterGen = CKM_X9_42_DH_PARAMETER_GEN,
+ DsaProbablisticParameterGen = CKM_DSA_PROBABLISTIC_PARAMETER_GEN,
+ DsaShaweTaylorParameterGen = CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN,
+ AesOfb = CKM_AES_OFB,
+ AesCfb64 = CKM_AES_CFB64,
+ AesCfb8 = CKM_AES_CFB8,
+ AesCfb128 = CKM_AES_CFB128,
+ AesCfb1 = CKM_AES_CFB1,
+ AesKeyWrap = CKM_AES_KEY_WRAP,
+ AesKeyWrapPad = CKM_AES_KEY_WRAP_PAD,
+ RsaPkcsTpm11 = CKM_RSA_PKCS_TPM_1_1,
+ RsaPkcsOaepTpm11 = CKM_RSA_PKCS_OAEP_TPM_1_1,
+ VendorDefined = CKM_VENDOR_DEFINED,
+ };
+
+enum class Notification : CK_NOTIFICATION
+ {
+ Surrender = CKN_SURRENDER,
+ OtpChanged = CKN_OTP_CHANGED,
+ };
+
+enum class ObjectClass : CK_OBJECT_CLASS
+ {
+ Data = CKO_DATA,
+ Certificate = CKO_CERTIFICATE,
+ PublicKey = CKO_PUBLIC_KEY,
+ PrivateKey = CKO_PRIVATE_KEY,
+ SecretKey = CKO_SECRET_KEY,
+ HwFeature = CKO_HW_FEATURE,
+ DomainParameters = CKO_DOMAIN_PARAMETERS,
+ Mechanism = CKO_MECHANISM,
+ OtpKey = CKO_OTP_KEY,
+ VendorDefined = CKO_VENDOR_DEFINED,
+ };
+
+enum class PseudoRandom : CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE
+ {
+ Pkcs5Pbkd2HmacSha1 = CKP_PKCS5_PBKD2_HMAC_SHA1,
+ Pkcs5Pbkd2HmacGostr3411 = CKP_PKCS5_PBKD2_HMAC_GOSTR3411,
+ Pkcs5Pbkd2HmacSha224 = CKP_PKCS5_PBKD2_HMAC_SHA224,
+ Pkcs5Pbkd2HmacSha256 = CKP_PKCS5_PBKD2_HMAC_SHA256,
+ Pkcs5Pbkd2HmacSha384 = CKP_PKCS5_PBKD2_HMAC_SHA384,
+ Pkcs5Pbkd2HmacSha512 = CKP_PKCS5_PBKD2_HMAC_SHA512,
+ Pkcs5Pbkd2HmacSha512224 = CKP_PKCS5_PBKD2_HMAC_SHA512_224,
+ Pkcs5Pbkd2HmacSha512256 = CKP_PKCS5_PBKD2_HMAC_SHA512_256,
+ };
+
+enum class SessionState : CK_STATE
+ {
+ RoPublicSession = CKS_RO_PUBLIC_SESSION,
+ RoUserFunctions = CKS_RO_USER_FUNCTIONS,
+ RwPublicSession = CKS_RW_PUBLIC_SESSION,
+ RwUserFunctions = CKS_RW_USER_FUNCTIONS,
+ RwSoFunctions = CKS_RW_SO_FUNCTIONS,
+ };
+
+enum class ReturnValue : CK_RV
+ {
+ OK = CKR_OK,
+ Cancel = CKR_CANCEL,
+ HostMemory = CKR_HOST_MEMORY,
+ SlotIdInvalid = CKR_SLOT_ID_INVALID,
+ GeneralError = CKR_GENERAL_ERROR,
+ FunctionFailed = CKR_FUNCTION_FAILED,
+ ArgumentsBad = CKR_ARGUMENTS_BAD,
+ NoEvent = CKR_NO_EVENT,
+ NeedToCreateThreads = CKR_NEED_TO_CREATE_THREADS,
+ CantLock = CKR_CANT_LOCK,
+ AttributeReadOnly = CKR_ATTRIBUTE_READ_ONLY,
+ AttributeSensitive = CKR_ATTRIBUTE_SENSITIVE,
+ AttributeTypeInvalid = CKR_ATTRIBUTE_TYPE_INVALID,
+ AttributeValueInvalid = CKR_ATTRIBUTE_VALUE_INVALID,
+ ActionProhibited = CKR_ACTION_PROHIBITED,
+ DataInvalid = CKR_DATA_INVALID,
+ DataLenRange = CKR_DATA_LEN_RANGE,
+ DeviceError = CKR_DEVICE_ERROR,
+ DeviceMemory = CKR_DEVICE_MEMORY,
+ DeviceRemoved = CKR_DEVICE_REMOVED,
+ EncryptedDataInvalid = CKR_ENCRYPTED_DATA_INVALID,
+ EncryptedDataLenRange = CKR_ENCRYPTED_DATA_LEN_RANGE,
+ FunctionCanceled = CKR_FUNCTION_CANCELED,
+ FunctionNotParallel = CKR_FUNCTION_NOT_PARALLEL,
+ FunctionNotSupported = CKR_FUNCTION_NOT_SUPPORTED,
+ KeyHandleInvalid = CKR_KEY_HANDLE_INVALID,
+ KeySizeRange = CKR_KEY_SIZE_RANGE,
+ KeyTypeInconsistent = CKR_KEY_TYPE_INCONSISTENT,
+ KeyNotNeeded = CKR_KEY_NOT_NEEDED,
+ KeyChanged = CKR_KEY_CHANGED,
+ KeyNeeded = CKR_KEY_NEEDED,
+ KeyIndigestible = CKR_KEY_INDIGESTIBLE,
+ KeyFunctionNotPermitted = CKR_KEY_FUNCTION_NOT_PERMITTED,
+ KeyNotWrappable = CKR_KEY_NOT_WRAPPABLE,
+ KeyUnextractable = CKR_KEY_UNEXTRACTABLE,
+ MechanismInvalid = CKR_MECHANISM_INVALID,
+ MechanismParamInvalid = CKR_MECHANISM_PARAM_INVALID,
+ ObjectHandleInvalid = CKR_OBJECT_HANDLE_INVALID,
+ OperationActive = CKR_OPERATION_ACTIVE,
+ OperationNotInitialized = CKR_OPERATION_NOT_INITIALIZED,
+ PinIncorrect = CKR_PIN_INCORRECT,
+ PinInvalid = CKR_PIN_INVALID,
+ PinLenRange = CKR_PIN_LEN_RANGE,
+ PinExpired = CKR_PIN_EXPIRED,
+ PinLocked = CKR_PIN_LOCKED,
+ SessionClosed = CKR_SESSION_CLOSED,
+ SessionCount = CKR_SESSION_COUNT,
+ SessionHandleInvalid = CKR_SESSION_HANDLE_INVALID,
+ SessionParallelNotSupported = CKR_SESSION_PARALLEL_NOT_SUPPORTED,
+ SessionReadOnly = CKR_SESSION_READ_ONLY,
+ SessionExists = CKR_SESSION_EXISTS,
+ SessionReadOnlyExists = CKR_SESSION_READ_ONLY_EXISTS,
+ SessionReadWriteSoExists = CKR_SESSION_READ_WRITE_SO_EXISTS,
+ SignatureInvalid = CKR_SIGNATURE_INVALID,
+ SignatureLenRange = CKR_SIGNATURE_LEN_RANGE,
+ TemplateIncomplete = CKR_TEMPLATE_INCOMPLETE,
+ TemplateInconsistent = CKR_TEMPLATE_INCONSISTENT,
+ TokenNotPresent = CKR_TOKEN_NOT_PRESENT,
+ TokenNotRecognized = CKR_TOKEN_NOT_RECOGNIZED,
+ TokenWriteProtected = CKR_TOKEN_WRITE_PROTECTED,
+ UnwrappingKeyHandleInvalid = CKR_UNWRAPPING_KEY_HANDLE_INVALID,
+ UnwrappingKeySizeRange = CKR_UNWRAPPING_KEY_SIZE_RANGE,
+ UnwrappingKeyTypeInconsistent = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT,
+ UserAlreadyLoggedIn = CKR_USER_ALREADY_LOGGED_IN,
+ UserNotLoggedIn = CKR_USER_NOT_LOGGED_IN,
+ UserPinNotInitialized = CKR_USER_PIN_NOT_INITIALIZED,
+ UserTypeInvalid = CKR_USER_TYPE_INVALID,
+ UserAnotherAlreadyLoggedIn = CKR_USER_ANOTHER_ALREADY_LOGGED_IN,
+ UserTooManyTypes = CKR_USER_TOO_MANY_TYPES,
+ WrappedKeyInvalid = CKR_WRAPPED_KEY_INVALID,
+ WrappedKeyLenRange = CKR_WRAPPED_KEY_LEN_RANGE,
+ WrappingKeyHandleInvalid = CKR_WRAPPING_KEY_HANDLE_INVALID,
+ WrappingKeySizeRange = CKR_WRAPPING_KEY_SIZE_RANGE,
+ WrappingKeyTypeInconsistent = CKR_WRAPPING_KEY_TYPE_INCONSISTENT,
+ RandomSeedNotSupported = CKR_RANDOM_SEED_NOT_SUPPORTED,
+ RandomNoRng = CKR_RANDOM_NO_RNG,
+ DomainParamsInvalid = CKR_DOMAIN_PARAMS_INVALID,
+ CurveNotSupported = CKR_CURVE_NOT_SUPPORTED,
+ BufferTooSmall = CKR_BUFFER_TOO_SMALL,
+ SavedStateInvalid = CKR_SAVED_STATE_INVALID,
+ InformationSensitive = CKR_INFORMATION_SENSITIVE,
+ StateUnsaveable = CKR_STATE_UNSAVEABLE,
+ CryptokiNotInitialized = CKR_CRYPTOKI_NOT_INITIALIZED,
+ CryptokiAlreadyInitialized = CKR_CRYPTOKI_ALREADY_INITIALIZED,
+ MutexBad = CKR_MUTEX_BAD,
+ MutexNotLocked = CKR_MUTEX_NOT_LOCKED,
+ NewPinMode = CKR_NEW_PIN_MODE,
+ NextOtp = CKR_NEXT_OTP,
+ ExceededMaxIterations = CKR_EXCEEDED_MAX_ITERATIONS,
+ FipsSelfTestFailed = CKR_FIPS_SELF_TEST_FAILED,
+ LibraryLoadFailed = CKR_LIBRARY_LOAD_FAILED,
+ PinTooWeak = CKR_PIN_TOO_WEAK,
+ PublicKeyInvalid = CKR_PUBLIC_KEY_INVALID,
+ FunctionRejected = CKR_FUNCTION_REJECTED,
+ VendorDefined = CKR_VENDOR_DEFINED,
+ };
+
+enum class UserType : CK_USER_TYPE
+ {
+ SO = CKU_SO,
+ User = CKU_USER,
+ ContextSpecific = CKU_CONTEXT_SPECIFIC,
+ };
+
+enum class PublicPointEncoding : uint32_t
+ {
+ Raw,
+ Der
+ };
+
+using FunctionListPtr = CK_FUNCTION_LIST_PTR;
+using VoidPtr = CK_VOID_PTR;
+using C_InitializeArgs = CK_C_INITIALIZE_ARGS;
+using CreateMutex = CK_CREATEMUTEX;
+using DestroyMutex = CK_DESTROYMUTEX;
+using LockMutex = CK_LOCKMUTEX;
+using UnlockMutex = CK_UNLOCKMUTEX;
+using Flags = CK_FLAGS;
+using Info = CK_INFO;
+using Bbool = CK_BBOOL;
+using SlotId = CK_SLOT_ID;
+using Ulong = CK_ULONG;
+using SlotInfo = CK_SLOT_INFO;
+using TokenInfo = CK_TOKEN_INFO;
+using Mechanism = CK_MECHANISM;
+using MechanismInfo = CK_MECHANISM_INFO;
+using Utf8Char = CK_UTF8CHAR;
+using Notify = CK_NOTIFY;
+using SessionHandle = CK_SESSION_HANDLE;
+using SessionInfo = CK_SESSION_INFO;
+using Attribute = CK_ATTRIBUTE;
+using ObjectHandle = CK_OBJECT_HANDLE;
+using Byte = CK_BYTE;
+using RsaPkcsOaepParams = CK_RSA_PKCS_OAEP_PARAMS;
+using RsaPkcsPssParams = CK_RSA_PKCS_PSS_PARAMS;
+using Ecdh1DeriveParams = CK_ECDH1_DERIVE_PARAMS;
+using Date = CK_DATE;
+
+BOTAN_DLL extern ReturnValue* ThrowException;
+
+const Bbool True = CK_TRUE;
+const Bbool False = CK_FALSE;
+
+inline Flags flags(Flag flags)
+ {
+ return static_cast<Flags>(flags);
+ }
+
+class Slot;
+
+/**
+* Initializes a token
+* @param slot The slot with the attached token that should be initialized
+* @param label The token label
+* @param so_pin PIN of the security officer. Will be set if the token is uninitialized other this has to be the current SO_PIN
+* @param pin The user PIN that will be set
+*/
+BOTAN_DLL void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin,
+ const secure_string& pin);
+
+/**
+* Change PIN with old PIN to new PIN
+* @param slot The slot with the attached token
+* @param old_pin The old user PIN
+* @param new_pin The new user PIN
+*/
+
+BOTAN_DLL void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin);
+
+/**
+* Change SO_PIN with old SO_PIN to new SO_PIN
+* @param slot The slot with the attached token
+* @param old_so_pin The old SO_PIN
+* @param new_so_pin The new SO_PIN
+*/
+BOTAN_DLL void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin);
+
+/**
+* Sets user PIN with SO_PIN
+* @param slot The slot with the attached token
+* @param so_pin PIN of the security officer
+* @param pin The user PIN that should be set
+*/
+BOTAN_DLL void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin);
+
+/// Provides access to all PKCS#11 functions
+class BOTAN_DLL LowLevel
+ {
+ public:
+
+ /// @param ptr the functon list pointer to use. Can be retrieved via `LowLevel::C_GetFunctionList`
+ explicit LowLevel(FunctionListPtr ptr);
+
+ ~LowLevel() BOTAN_NOEXCEPT;
+
+ /****************************** General purpose functions ******************************/
+
+ /**
+ * C_Initialize initializes the Cryptoki library.
+ * @param init_args if this is not nullptr, it gets cast to (`C_InitializeArgs`) and dereferenced
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CantLock \li CryptokiAlreadyInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li NeedToCreateThreads \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_Initialize(VoidPtr init_args,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Finalize indicates that an application is done with the Cryptoki library.
+ * @param reserved reserved. Should be nullptr
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_Finalize(VoidPtr reserved,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetInfo returns general information about Cryptoki.
+ * @param info_ptr location that receives information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetInfo(Info* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetFunctionList returns the function list.
+ * @param pkcs11_module The PKCS#11 module
+ * @param function_list_ptr_ptr receives pointer to function list
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ static bool C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr,
+ ReturnValue* return_value = ThrowException);
+
+ /****************************** Slot and token management functions ******************************/
+
+ /**
+ * C_GetSlotList obtains a list of slots in the system.
+ * @param token_present only slots with tokens
+ * @param slot_list_ptr receives array of slot IDs
+ * @param count_ptr receives number of slots
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotList(Bbool token_present,
+ SlotId* slot_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSlotList obtains a list of slots in the system.
+ * @param token_present only slots with tokens
+ * @param slot_ids receives vector of slot IDs
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotList(bool token_present,
+ std::vector<SlotId>& slot_ids,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSlotInfo obtains information about a particular slot in the system.
+ * @param slot_id the ID of the slot
+ * @param info_ptr receives the slot information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li SlotIdInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotInfo(SlotId slot_id,
+ SlotInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetTokenInfo obtains information about a particular token in the system.
+ * @param slot_id ID of the token's slot
+ * @param info_ptr receives the token information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SlotIdInvalid
+ * \li TokenNotPresent \li TokenNotRecognized \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetTokenInfo(SlotId slot_id,
+ TokenInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_WaitForSlotEvent waits for a slot event (token insertion, removal, etc.) to occur.
+ * @param flags blocking/nonblocking flag
+ * @param slot_ptr location that receives the slot ID
+ * @param reserved reserved. Should be NULL_PTR
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li NoEvent
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_WaitForSlotEvent(Flags flags,
+ SlotId* slot_ptr,
+ VoidPtr reserved,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismList obtains a list of mechanism types supported by a token.
+ * @param slot_id ID of token's slot
+ * @param mechanism_list_ptr gets mech. array
+ * @param count_ptr gets # of mechs.
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismList(SlotId slot_id,
+ MechanismType* mechanism_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismList obtains a list of mechanism types supported by a token.
+ * @param slot_id ID of token's slot
+ * @param mechanisms receives vector of supported mechanisms
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismList(SlotId slot_id,
+ std::vector<MechanismType>& mechanisms,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismInfo obtains information about a particular mechanism possibly supported by a token.
+ * @param slot_id ID of the token's slot
+ * @param type type of mechanism
+ * @param info_ptr receives mechanism info
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li MechanismInvalid \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismInfo(SlotId slot_id,
+ MechanismType type,
+ MechanismInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitToken initializes a token.
+ * @param slot_id ID of the token's slot
+ * @param so_pin_ptr the SO's initial PIN
+ * @param so_pin_len length in bytes of the SO_PIN
+ * @param label_ptr 32-byte token label (blank padded)
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinLocked \li SessionExists
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_InitToken(SlotId slot_id,
+ Utf8Char* so_pin_ptr,
+ Ulong so_pin_len,
+ Utf8Char* label_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitToken initializes a token.
+ * @param slot_id ID of the token's slot
+ * @param so_pin the SO's initial PIN
+ * @param label token label (at max 32 bytes long)
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinLocked \li SessionExists
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_InitToken(SlotId slot_id,
+ const std::vector<byte, TAlloc>& so_pin,
+ const std::string& label,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::string padded_label = label;
+ if(label.size() < 32)
+ {
+ padded_label.insert(padded_label.end(), 32 - label.size(), ' ');
+ }
+
+ return C_InitToken(slot_id, reinterpret_cast< Utf8Char* >(const_cast< byte* >(so_pin.data())),
+ so_pin.size(), reinterpret_cast< Utf8Char* >(const_cast< char* >(padded_label.c_str())), return_value);
+ }
+
+ /**
+ * C_InitPIN initializes the normal user's PIN.
+ * @param session the session's handle
+ * @param pin_ptr the normal user's PIN
+ * @param pin_len length in bytes of the PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinInvalid \li PinLenRange \li SessionClosed
+ * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected
+ * \li UserNotLoggedIn \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_InitPIN(SessionHandle session,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitPIN initializes the normal user's PIN.
+ * @param session the session's handle
+ * @param pin the normal user's PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinInvalid \li PinLenRange \li SessionClosed
+ * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected
+ * \li UserNotLoggedIn \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_InitPIN(SessionHandle session,
+ const std::vector<byte, TAlloc>& pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_InitPIN(session, reinterpret_cast< Utf8Char* >(const_cast< byte* >(pin.data())), pin.size(), return_value);
+ }
+
+ /**
+ * C_SetPIN modifies the PIN of the user who is logged in.
+ * @param session the session's handle
+ * @param old_pin_ptr the old PIN
+ * @param old_len length of the old PIN
+ * @param new_pin_ptr the new PIN
+ * @param new_len length of the new PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinInvalid \li PinLenRange
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_SetPIN(SessionHandle session,
+ Utf8Char* old_pin_ptr,
+ Ulong old_len,
+ Utf8Char* new_pin_ptr,
+ Ulong new_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetPIN modifies the PIN of the user who is logged in.
+ * @param session the session's handle
+ * @param old_pin the old PIN
+ * @param new_pin the new PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinInvalid \li PinLenRange
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SetPIN(SessionHandle session,
+ const std::vector<byte, TAlloc>& old_pin,
+ const std::vector<byte, TAlloc>& new_pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_SetPIN(session,
+ reinterpret_cast< Utf8Char* >(const_cast< byte* >(old_pin.data())), old_pin.size(),
+ reinterpret_cast< Utf8Char* >(const_cast< byte* >(new_pin.data())), new_pin.size(),
+ return_value);
+ }
+
+
+ /****************************** Session management ******************************/
+
+ /**
+ * C_OpenSession opens a session between an application and a token.
+ * @param slot_id the slot's ID
+ * @param flags from CK_SESSION_INFO
+ * @param application passed to callback
+ * @param notify callback function
+ * @param session_ptr gets session handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionCount
+ * \li SessionParallelNotSupported \li SessionReadWriteSoExists \li SlotIdInvalid
+ * \li TokenNotPresent \li TokenNotRecognized \li TokenWriteProtected
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_OpenSession(SlotId slot_id,
+ Flags flags,
+ VoidPtr application,
+ Notify notify,
+ SessionHandle* session_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CloseSession closes a session between an application and a token.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_CloseSession(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CloseAllSessions closes all sessions with a token.
+ * @param slot_id the token's slot
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SlotIdInvalid
+ * \li TokenNotPresent
+ * @return true on success, false otherwise
+ */
+ bool C_CloseAllSessions(SlotId slot_id,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSessionInfo obtains information about the session.
+ * @param session the session's handle
+ * @param info receives session info
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetSessionInfo(SessionHandle session,
+ SessionInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetOperationState obtains the state of the cryptographic operation in a session.
+ * @param session session's handle
+ * @param operation_state_ptr gets state
+ * @param operation_state_len_ptr gets state length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li StateUnsaveable \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong* operation_state_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetOperationState restores the state of the cryptographic operation in a session.
+ * @param session session's handle
+ * @param operation_state_ptr holds state
+ * @param operation_state_len holds state length
+ * @param encryption_key en/decryption key
+ * @param authentication_key sign/verify key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li KeyChanged \li KeyNeeded
+ * \li KeyNotNeeded \li OK \li SavedStateInvalid
+ * \li SessionClosed \li SessionHandleInvalid \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_SetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong operation_state_len,
+ ObjectHandle encryption_key,
+ ObjectHandle authentication_key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Login logs a user into a token.
+ * @param session the session's handle
+ * @param user_type the user type
+ * @param pin_ptr the user's PIN
+ * @param pin_len the length of the PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li PinIncorrect
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn
+ * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Login(SessionHandle session,
+ UserType user_type,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Login logs a user into a token.
+ * @param session the session's handle
+ * @param user_type the user type
+ * @param pin the user or security officer's PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li PinIncorrect
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn
+ * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_Login(SessionHandle session,
+ UserType user_type,
+ const std::vector<byte, TAlloc>& pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_Login(session, user_type, reinterpret_cast< Utf8Char* >(const_cast< byte* >(pin.data())), pin.size(),
+ return_value);
+ }
+
+ /**
+ * C_Logout logs a user out from a token.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_Logout(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Object management functions ******************************/
+
+ /**
+ * C_CreateObject creates a new object.
+ * @param session the session's handle
+ * @param attribute_template_ptr the object's template
+ * @param count attributes in template
+ * @param object_ptr gets new object's handle.
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_CreateObject(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* object_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CopyObject copies an object, creating a new object for the copy.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr template for new object
+ * @param count attributes in template
+ * @param new_object_ptr receives handle of copy
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateInconsistent \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_CopyObject(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* new_object_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DestroyObject destroys an object.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TokenWriteProtected
+ * @return true on success, false otherwise
+ */
+ bool C_DestroyObject(SessionHandle session,
+ ObjectHandle object,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetObjectSize gets the size of an object in bytes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param size_ptr receives size of object
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li InformationSensitive
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetObjectSize(SessionHandle session,
+ ObjectHandle object,
+ Ulong* size_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetAttributeValue obtains the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr specifies attrs; gets vals
+ * @param count attributes in template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetAttributeValue obtains the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_values specifies attrs; gets vals
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ std::map<AttributeType, std::vector<byte, TAlloc>>& attribute_values,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::vector<Attribute> getter_template;
+
+ for(const auto& entry : attribute_values)
+ {
+ getter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), nullptr, 0 });
+ }
+
+ bool success = C_GetAttributeValue(session, object, const_cast< Attribute* >(getter_template.data()),
+ getter_template.size(), return_value);
+
+ if(!success)
+ {
+ return success;
+ }
+
+ size_t i = 0;
+ for(auto& entry : attribute_values)
+ {
+ entry.second.clear();
+ entry.second.resize(getter_template.at(i).ulValueLen);
+ getter_template.at(i).pValue = const_cast< byte* >(entry.second.data());
+ i++;
+ }
+
+ return C_GetAttributeValue(session, object, const_cast< Attribute* >(getter_template.data()), getter_template.size(),
+ return_value);
+ }
+
+ /**
+ * C_SetAttributeValue modifies the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr specifies attrs and values
+ * @param count attributes in template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetAttributeValue modifies the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attributes specifies attrs and values
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ std::map<AttributeType, std::vector<byte, TAlloc>>& attribute_values,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::vector<Attribute> setter_template;
+
+ for(auto& entry : attribute_values)
+ {
+ setter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), entry.second.data(), static_cast<CK_ULONG>(entry.second.size()) });
+ }
+
+ return C_SetAttributeValue(session, object, const_cast< Attribute* >(setter_template.data()), setter_template.size(),
+ return_value);
+ }
+
+ /**
+ * C_FindObjectsInit initializes a search for token and session objects that match a template.
+ * @param session the session's handle
+ * @param attribute_template_ptr attribute values to match
+ * @param count attrs in search template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeTypeInvalid \li AttributeValueInvalid
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjectsInit(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_FindObjects continues a search for token and session objects that match a template, obtaining additional object handles.
+ * @param session session's handle
+ * @param object gets obj. handles
+ * @param max_object_count max handles to get
+ * @param object_count actual # returned
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjects(SessionHandle session,
+ ObjectHandle* object_ptr,
+ Ulong max_object_count,
+ Ulong* object_count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_FindObjectsFinal finishes a search for token and session objects.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjectsFinal(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Encryption functions ******************************/
+
+ /**
+ * C_EncryptInit initializes an encryption operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the encryption mechanism
+ * @param key handle of encryption key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyFunctionNotPermitted
+ * \li KeyHandleInvalid \li KeySizeRange \li KeyTypeInconsistent
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Encrypt encrypts single-part data.
+ * @param session session's handle
+ * @param data_ptr the plaintext data
+ * @param encrypted_data_len_ptr bytes of plaintext
+ * @param encrypted_data gets ciphertext
+ * @param encrypted_data_len gets c-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Encrypt(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* encrypted_data,
+ Ulong* encrypted_data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Encrypt encrypts single-part data.
+ * @param session session's handle
+ * @param plaintext_data the plaintext data
+ * @param encrypted_data gets ciphertext
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Encrypt(SessionHandle session,
+ const std::vector<byte, TAllocA>& plaintext_data,
+ std::vector<byte, TAllocB>& encrypted_data,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong encrypted_size = 0;
+ if(!C_Encrypt(session, const_cast<Byte*>((plaintext_data.data())), plaintext_data.size(), nullptr, &encrypted_size,
+ return_value))
+ {
+ return false;
+ }
+
+ encrypted_data.resize(encrypted_size);
+ return C_Encrypt(session, const_cast<Byte*>(plaintext_data.data()), plaintext_data.size(), encrypted_data.data(),
+ &encrypted_size, return_value);
+ }
+
+ /**
+ * C_EncryptUpdate continues a multiple-part encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext data len
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_EncryptFinal finishes a multiple-part encryption operation.
+ * @param session session handle
+ * @param last_encrypted_part_ptr last c-text
+ * @param last_encrypted_part_len_ptr gets last size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptFinal(SessionHandle session,
+ Byte* last_encrypted_part_ptr,
+ Ulong* last_encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Decryption functions ******************************/
+
+ /**
+ * C_DecryptInit initializes a decryption operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the decryption mechanism
+ * @param key handle of decryption key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Decrypt decrypts encrypted data in a single part.
+ * @param session session's handle
+ * @param encrypted_data_ptr ciphertext
+ * @param encrypted_data_len ciphertext length
+ * @param data_ptr gets plaintext
+ * @param data_len_ptr gets p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_Decrypt(SessionHandle session,
+ Byte* encrypted_data_ptr,
+ Ulong encrypted_data_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Decrypt decrypts encrypted data in a single part.
+ * @param session session's handle
+ * @param encrypted_data ciphertext
+ * @param decrypted_data gets plaintext
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Decrypt(SessionHandle session,
+ const std::vector<byte, TAllocA>& encrypted_data,
+ std::vector<byte, TAllocB>& decrypted_data,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong decrypted_size = 0;
+ if(!C_Decrypt(session, const_cast<Byte*>((encrypted_data.data())), encrypted_data.size(), nullptr, &decrypted_size,
+ return_value))
+ {
+ return false;
+ }
+
+ decrypted_data.resize(decrypted_size);
+ return C_Decrypt(session, const_cast<Byte*>(encrypted_data.data()), encrypted_data.size(), decrypted_data.data(),
+ &decrypted_size, return_value);
+ }
+
+ /**
+ * C_DecryptUpdate continues a multiple-part decryption operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr encrypted data
+ * @param encrypted_part_len input length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DecryptFinal finishes a multiple-part decryption operation.
+ * @param session the session's handle
+ * @param last_part_ptr gets plaintext
+ * @param last_part_len_ptr p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptFinal(SessionHandle session,
+ Byte* last_part_ptr,
+ Ulong* last_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Message digesting functions ******************************/
+
+ /**
+ * C_DigestInit initializes a message-digesting operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the digesting mechanism
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DigestInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Digest digests data in a single part.
+ * @param session the session's handle
+ * @param data_ptr data to be digested
+ * @param data_len bytes of data to digest
+ * @param digest_ptr gets the message digest
+ * @param digest_len_ptr gets digest length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Digest(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestUpdate continues a multiple-part message-digesting operation.
+ * @param session the session's handle
+ * @param part_ptr data to be digested
+ * @param part_len bytes of data to be digested
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestKey continues a multi-part message-digesting operation, by digesting the value of a secret key as part of the data already digested.
+ * @param session the session's handle
+ * @param key secret key to digest
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyHandleInvalid
+ * \li KeyIndigestible \li KeySizeRange \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestKey(SessionHandle session,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestFinal finishes a multiple-part message-digesting operation.
+ * @param session the session's handle
+ * @param digest_ptr gets the message digest
+ * @param digest_len_ptr gets byte count of digest
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestFinal(SessionHandle session,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Signing and MACing functions ******************************/
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param mechanism_ptr the signature mechanism
+ * @param key handle of signature key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param data_ptr the data to sign
+ * @param data_len count of bytes to sign
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ bool C_Sign(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param data the data to sign
+ * @param signature gets the signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Sign(SessionHandle session,
+ const std::vector<byte, TAllocA>& data,
+ std::vector<byte, TAllocB>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong signature_size = 0;
+ if(!C_Sign(session, const_cast<Byte*>((data.data())), data.size(), nullptr, &signature_size, return_value))
+ {
+ return false;
+ }
+
+ signature.resize(signature_size);
+ return C_Sign(session, const_cast<Byte*>(data.data()), data.size(), signature.data(), &signature_size, return_value);
+ }
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param part_ptr the data to sign
+ * @param part_len count of bytes to sign
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param part the data to sign
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SignUpdate(SessionHandle session,
+ const std::vector<byte, TAlloc>& part,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_SignUpdate(session, const_cast<Byte*>(part.data()), part.size(), return_value);
+ }
+
+ /**
+ * C_SignFinal finishes a multiple-part signature operation, returning the signature.
+ * @param session the session's handle
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ bool C_SignFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignFinal finishes a multiple-part signature operation, returning the signature.
+ * @param session the session's handle
+ * @param signature gets the signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SignFinal(SessionHandle session,
+ std::vector<byte, TAlloc>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong signature_size = 0;
+ if(!C_SignFinal(session, nullptr, &signature_size, return_value))
+ {
+ return false;
+ }
+
+ signature.resize(signature_size);
+ return C_SignFinal(session, signature.data(), &signature_size, return_value);
+ }
+
+ /**
+ * C_SignRecoverInit initializes a signature operation, where the data can be recovered from the signature.
+ * @param session the session's handle
+ * @param mechanism_ptr the signature mechanism
+ * @param key handle of the signature key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignRecover signs data in a single operation, where the data can be recovered from the signature.
+ * @param session the session's handle
+ * @param data_ptr the data to sign
+ * @param data_len count of bytes to sign
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignRecover(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Functions for verifying signatures and MACs ******************************/
+
+ /**
+ * C_VerifyInit initializes a verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature (e.g. DSA).
+ * @param session the session's handle
+ * @param mechanism_ptr the verification mechanism
+ * @param key verification key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param data_ptr signed data
+ * @param data_len length of signed data
+ * @param signature_ptr signature
+ * @param signature_len signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li SignatureInvalid \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_Verify(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param data signed data
+ * @param signature signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li SignatureInvalid \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Verify(SessionHandle session,
+ const std::vector<byte, TAllocA>& data,
+ std::vector<byte, TAllocB>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_Verify(session, const_cast<Byte*>(data.data()), data.size(), signature.data(), signature.size(), return_value);
+ }
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param part_ptr signed data
+ * @param part_len length of signed data
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * 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.
+ * @param session the session's handle
+ * @param part signed data
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_VerifyUpdate(SessionHandle session,
+ std::vector<byte, TAlloc> part,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_VerifyUpdate(session, part.data(), part.size(), return_value);
+ }
+
+ /**
+ * C_VerifyFinal finishes a multiple-part verification operation, checking the signature.
+ * @param session the session's handle
+ * @param signature_ptr signature to verify
+ * @param signature_len signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li SignatureInvalid
+ * \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_VerifyRecoverInit initializes a signature verification operation, where the data is recovered from the signature.
+ * @param session the session's handle
+ * @param mechanism_ptr the verification mechanism
+ * @param key verification key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_VerifyRecover verifies a signature in a single-part operation, where the data is recovered from the signature.
+ * @param session the session's handle
+ * @param signature_ptr signature to verify
+ * @param signature_len signature length
+ * @param data_ptr gets signed data
+ * @param data_len_ptr gets signed data len
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li SignatureLenRange \li SignatureInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyRecover(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Dual-purpose cryptographic functions ******************************/
+
+ /**
+ * C_DigestEncryptUpdate continues a multiple-part digesting and encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext length
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const ;
+
+ /**
+ * C_DecryptDigestUpdate continues a multiple-part decryption and digesting operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr ciphertext
+ * @param encrypted_part_len ciphertext length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr gets plaintext len
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptDigestUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignEncryptUpdate continues a multiple-part signing and encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext length
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DecryptVerifyUpdate continues a multiple-part decryption and verify operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr ciphertext
+ * @param encrypted_part_len ciphertext length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr gets p-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li EncryptedDataInvalid \li EncryptedDataLenRange
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptVerifyUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Key management functions ******************************/
+
+ /**
+ * C_GenerateKey generates a secret key, creating a new key object.
+ * @param session the session's handle
+ * @param mechanism_ptr key generation mech.
+ * @param attribute_template_ptr template for new key
+ * @param count # of attrs in template
+ * @param key_ptr gets handle of new key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GenerateKeyPair generates a public-key/private-key pair, creating new key objects.
+ * @param session session handle
+ * @param mechanism_ptr key-gen mech.
+ * @param public_key_template_ptr template for pub. key
+ * @param public_key_attribute_count # pub. attrs.
+ * @param private_key_template_ptr template for priv. key
+ * @param private_key_attribute_count # priv. attrs.
+ * @param public_key_ptr gets pub. key handle
+ * @param private_key_ptr gets priv. key handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateKeyPair(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* public_key_template_ptr,
+ Ulong public_key_attribute_count,
+ Attribute* private_key_template_ptr,
+ Ulong private_key_attribute_count,
+ ObjectHandle* public_key_ptr,
+ ObjectHandle* private_key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_WrapKey wraps (i.e., encrypts) a key.
+ * @param session the session's handle
+ * @param mechanism_ptr the wrapping mechanism
+ * @param wrapping_key wrapping key
+ * @param key key to be wrapped
+ * @param wrapped_key_ptr gets wrapped key
+ * @param wrapped_key_len_ptr gets wrapped key size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li KeyHandleInvalid \li KeyNotWrappable
+ * \li KeySizeRange \li KeyUnextractable \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li WrappingKeyHandleInvalid \li WrappingKeySizeRange
+ * \li WrappingKeyTypeInconsistent
+ * @return true on success, false otherwise
+ */
+ bool C_WrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle wrapping_key,
+ ObjectHandle key,
+ Byte* wrapped_key_ptr,
+ Ulong* wrapped_key_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object.
+ * @param session session's handle
+ * @param mechanism_ptr unwrapping mech.
+ * @param unwrapping_key unwrapping key
+ * @param wrapped_key_ptr the wrapped key
+ * @param wrapped_key_len wrapped key len
+ * @param attribute_template_ptr new key template
+ * @param attribute_count template length
+ * @param key_ptr gets new handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li BufferTooSmall \li CryptokiNotInitialized
+ * \li CurveNotSupported \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li DomainParamsInvalid \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateIncomplete
+ * \li TemplateInconsistent \li TokenWriteProtected \li UnwrappingKeyHandleInvalid
+ * \li UnwrappingKeySizeRange \li UnwrappingKeyTypeInconsistent \li UserNotLoggedIn
+ * \li WrappedKeyInvalid \li WrappedKeyLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_UnwrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle unwrapping_key,
+ Byte* wrapped_key_ptr,
+ Ulong wrapped_key_len,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DeriveKey derives a key from a base key, creating a new key object.
+ * @param session session's handle
+ * @param mechanism_ptr key deriv. mech.
+ * @param base_key base key
+ * @param attribute_template_ptr new key template
+ * @param attribute_count template length
+ * @param key_ptr gets new handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyHandleInvalid
+ * \li KeySizeRange \li KeyTypeInconsistent \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DeriveKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle base_key,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Random number generation functions ******************************/
+
+ /**
+ * C_SeedRandom mixes additional seed material into the token's random number generator.
+ * @param session the session's handle
+ * @param seed_ptr the seed material
+ * @param seed_len length of seed material
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationActive \li RandomSeedNotSupported
+ * \li RandomNoRng \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SeedRandom(SessionHandle session,
+ Byte* seed_ptr,
+ Ulong seed_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GenerateRandom generates random data.
+ * @param session the session's handle
+ * @param random_data_ptr receives the random data
+ * @param random_len # of bytes to generate
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationActive \li RandomNoRng
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateRandom(SessionHandle session,
+ Byte* random_data_ptr,
+ Ulong random_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Parallel function management functions ******************************/
+
+ /**
+ * C_GetFunctionStatus is a legacy function; it obtains an updated status of a function running in parallel with an application.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel
+ * \li GeneralError \li HostMemory \li SessionHandleInvalid
+ * \li SessionClosed
+ * @return true on success, false otherwise
+ */
+ bool C_GetFunctionStatus(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CancelFunction is a legacy function; it cancels a function running in parallel.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel
+ * \li GeneralError \li HostMemory \li SessionHandleInvalid
+ * \li SessionClosed
+ * @return true on success, false otherwise
+ */
+ bool C_CancelFunction(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ private:
+ const FunctionListPtr m_func_list_ptr;
+ };
+
+class PKCS11_Error : public Exception
+ {
+ public:
+ explicit PKCS11_Error(const std::string& what) :
+ Exception("PKCS11 error", what)
+ {
+ }
+ };
+
+class PKCS11_ReturnError : public PKCS11_Error
+ {
+ public:
+ explicit PKCS11_ReturnError(ReturnValue return_val) :
+ PKCS11_Error(std::to_string(static_cast< uint32_t >(return_val))),
+ m_return_val(return_val)
+ {}
+
+ inline ReturnValue get_return_value() const
+ {
+ return m_return_val;
+ }
+
+ private:
+ const ReturnValue m_return_val;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecc_key.cpp b/src/lib/prov/pkcs11/p11_ecc_key.cpp
new file mode 100644
index 000000000..4382b8c2b
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecc_key.cpp
@@ -0,0 +1,137 @@
+/*
+* PKCS#11 ECC
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecc_key.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+#include <botan/workfactor.h>
+#include <botan/ber_dec.h>
+
+namespace Botan {
+namespace PKCS11 {
+namespace {
+/// Converts a DER-encoded ANSI X9.62 ECPoint to PointGFp
+PointGFp decode_public_point(const secure_vector<byte>& ec_point_data, const CurveGFp& curve)
+ {
+ secure_vector<byte> ec_point;
+ BER_Decoder(ec_point_data).decode(ec_point, OCTET_STRING);
+ return OS2ECP(ec_point, curve);
+ }
+}
+
+EC_PublicKeyGenerationProperties::EC_PublicKeyGenerationProperties(const std::vector<byte>& ec_params)
+ : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ }
+
+EC_PublicKeyImportProperties::EC_PublicKeyImportProperties(const std::vector<byte>& ec_params,
+ const std::vector<byte>& ec_point)
+ : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_ec_point(ec_point)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ add_binary(AttributeType::EcPoint, m_ec_point);
+ }
+
+PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, ObjectHandle handle)
+ : EC_PublicKey(), Object(session, handle)
+ {
+ secure_vector<byte> ec_parameters = get_attribute_value(AttributeType::EcParams);
+ m_domain_params = EC_Group(unlock(ec_parameters));
+ m_public_key = decode_public_point(get_attribute_value(AttributeType::EcPoint), m_domain_params.get_curve());
+ m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT;
+ }
+
+size_t PKCS11_EC_PublicKey::max_input_bits() const
+ {
+ return domain().get_order().bits();
+ }
+
+PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : Object(session, props)
+ {
+ m_domain_params = EC_Group(props.ec_params());
+
+ secure_vector<byte> ec_point;
+ BER_Decoder(props.ec_point()).decode(ec_point, OCTET_STRING);
+ m_public_key = OS2ECP(ec_point, m_domain_params.get_curve());
+ m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT;
+ }
+
+EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector<byte>& ec_params, const BigInt& value)
+ : PrivateKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_value(value)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ add_binary(AttributeType::Value, BigInt::encode(m_value));
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle)
+ : Object(session, handle), m_domain_params(), m_public_key(), m_point_encoding(PublicPointEncoding::Der)
+ {
+ secure_vector<byte> ec_parameters = get_attribute_value(AttributeType::EcParams);
+ m_domain_params = EC_Group(unlock(ec_parameters));
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : Object(session, props)
+ {
+ m_domain_params = EC_Group(props.ec_params());
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : Object(session)
+ {
+ m_domain_params = EC_Group(ec_params);
+
+ EC_PublicKeyGenerationProperties pub_key_props(ec_params);
+ pub_key_props.set_verify(true);
+ pub_key_props.set_private(false);
+ pub_key_props.set_token(false); // don't create a persistent public key object
+
+ ObjectHandle pub_key_handle = 0;
+ m_handle = 0;
+ Mechanism mechanism = { CKM_EC_KEY_PAIR_GEN, nullptr, 0 };
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_key_props.data(), pub_key_props.count(), props.data(), props.count(),
+ &pub_key_handle, &m_handle);
+
+ Object public_key(session, pub_key_handle);
+ m_public_key = decode_public_point(public_key.get_attribute_value(AttributeType::EcPoint), m_domain_params.get_curve());
+ }
+
+size_t PKCS11_EC_PrivateKey::max_input_bits() const
+ {
+ return m_domain_params.get_order().bits();
+ }
+
+std::vector<byte> PKCS11_EC_PrivateKey::x509_subject_public_key() const
+ {
+ return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED));
+ }
+
+size_t PKCS11_EC_PrivateKey::estimated_strength() const
+ {
+ return ecp_work_factor(domain().get_curve().get_p().bits());
+ }
+
+bool PKCS11_EC_PrivateKey::check_key(RandomNumberGenerator&, bool) const
+ {
+ return m_public_key.on_the_curve();
+ }
+
+AlgorithmIdentifier PKCS11_EC_PrivateKey::algorithm_identifier() const
+ {
+ return AlgorithmIdentifier(get_oid(), domain().DER_encode(EC_DOMPAR_ENC_EXPLICIT));
+ }
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecc_key.h b/src/lib/prov/pkcs11/p11_ecc_key.h
new file mode 100644
index 000000000..a32a78339
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecc_key.h
@@ -0,0 +1,229 @@
+/*
+* PKCS#11 ECC
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECC_H__
+#define BOTAN_P11_ECC_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+#include <botan/p11_object.h>
+#include <botan/pk_keys.h>
+#include <botan/ecc_key.h>
+#include <botan/ec_group.h>
+#include <botan/rng.h>
+#include <botan/alg_id.h>
+
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Session;
+
+/// Properties for generating a PKCS#11 EC public key
+class BOTAN_DLL EC_PublicKeyGenerationProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ EC_PublicKeyGenerationProperties(const std::vector<byte>& ec_params);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ };
+
+/// Properties for importing a PKCS#11 EC public key
+class BOTAN_DLL EC_PublicKeyImportProperties final : public PublicKeyProperties
+ {
+ public:
+ /**
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param ec_point DER-encoding of ANSI X9.62 ECPoint value Q
+ */
+ EC_PublicKeyImportProperties(const std::vector<byte>& ec_params, const std::vector<byte>& ec_point);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ /// @return the DER-encoding of the ec public point according to ANSI X9.62
+ inline const std::vector<byte>& ec_point() const
+ {
+ return m_ec_point;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ const std::vector<byte> m_ec_point;
+ };
+
+/// Represents a PKCS#11 EC public key
+class BOTAN_DLL PKCS11_EC_PublicKey : public virtual EC_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PublicKey;
+
+ /**
+ * Creates a PKCS11_EC_PublicKey object from an existing PKCS#11 EC public key
+ * @param session the session to use
+ * @param handle the handle of the ecc public key
+ */
+ PKCS11_EC_PublicKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports an EC public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props);
+
+ size_t max_input_bits() const override;
+ };
+
+/// Properties for generating a PKCS#11 EC private key
+class BOTAN_DLL EC_PrivateKeyGenerationProperties final : public PrivateKeyProperties
+ {
+ public:
+ EC_PrivateKeyGenerationProperties()
+ : PrivateKeyProperties(KeyType::Ec)
+ {}
+ };
+
+/// Properties for importing a PKCS#11 EC private key
+class BOTAN_DLL EC_PrivateKeyImportProperties final : public PrivateKeyProperties
+ {
+ public:
+ /**
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param value ANSI X9.62 private value d
+ */
+ EC_PrivateKeyImportProperties(const std::vector<byte>& ec_params, const BigInt& value);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ /// @return the value of the ec private key
+ inline const BigInt& value() const
+ {
+ return m_value;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ const BigInt m_value;
+ };
+
+// note: don't inherit from PKCS11_EC_PublicKey: a private key object IS NOT A public key object on a smartcard (-> two different objects)
+// note: don't inherit from EC_PublicKey: the public key can not be extracted from a PKCS11-EC-PrivateKey (its only attributes are CKA_EC_PARAMS and CKA_VALUE)
+/// Represents a PKCS#11 EC private key
+class BOTAN_DLL PKCS11_EC_PrivateKey : public virtual Private_Key,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PrivateKey;
+
+ /**
+ * Creates a PKCS11_EC_PrivateKey object from an existing PKCS#11 EC private key
+ * @param session the session to use
+ * @param handle the handle of the EC private key
+ */
+ PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports an EC private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props);
+
+ /**
+ * Generates a PKCS#11 EC private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_EC_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props);
+
+ /// @returns the domain of the EC private key
+ inline const EC_Group& domain() const
+ {
+ return m_domain_params;
+ }
+
+ /**
+ * Sets the associated public point of this private key
+ * @param point the public point
+ * @param point_encoding encoding of the point (default DER-encoded)
+ */
+ void set_public_point(const PointGFp& point, PublicPointEncoding point_encoding = PublicPointEncoding::Der)
+ {
+ m_public_key = point;
+ m_point_encoding = point_encoding;
+ }
+
+ /**
+ * Gets the public_point
+ * @note: the public key must be set using `set_public_point`
+ * because it is not possible to infer the public key from a PKCS#11 EC private key
+ * @return the public point of the private key
+ * @throws Exception if the public point was not set using set_public_point()
+ */
+
+ const PointGFp& public_point() const
+ {
+ if(m_public_key.is_zero())
+ {
+ throw Exception("Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible.");
+ }
+ return m_public_key;
+ }
+
+ /// @return the encoding format for the public point when it is passed to cryptoki functions as an argument
+ PublicPointEncoding point_encoding() const
+ {
+ return m_point_encoding;
+ }
+
+ // Private_Key methods
+
+ std::size_t max_input_bits() const override;
+
+ std::vector<byte> x509_subject_public_key() const override;
+
+ std::size_t estimated_strength() const override;
+
+ bool check_key(RandomNumberGenerator&, bool) const override;
+
+ AlgorithmIdentifier algorithm_identifier() const override;
+
+ private:
+ EC_Group m_domain_params;
+ PointGFp m_public_key;
+ PublicPointEncoding m_point_encoding;
+ };
+}
+
+}
+
+#endif
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdh.cpp b/src/lib/prov/pkcs11/p11_ecdh.cpp
new file mode 100644
index 000000000..82c1716af
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdh.cpp
@@ -0,0 +1,151 @@
+/*
+* PKCS#11 ECDH
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecdh.h>
+
+#if defined(BOTAN_HAS_ECDH)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#else
+ #include <botan/auto_rng.h>
+#endif
+
+namespace Botan {
+
+namespace PKCS11 {
+
+ECDH_PublicKey PKCS11_ECDH_PublicKey::export_key() const
+ {
+ return ECDH_PublicKey(domain(), public_point());
+ }
+
+ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const
+ {
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ System_RNG rng;
+#else
+ AutoSeeded_RNG rng;
+#endif
+ auto priv_key = get_attribute_value(AttributeType::Value);
+
+ return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key));
+ }
+
+secure_vector<byte> PKCS11_ECDH_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+namespace {
+class PKCS11_ECDH_KA_Operation : public PK_Ops::Key_Agreement
+ {
+ public:
+ typedef PKCS11_EC_PrivateKey Key_Type;
+
+ static PKCS11_ECDH_KA_Operation* make_ecdh(const Spec& spec, bool use_cofactor)
+ {
+ try
+ {
+ if(auto* key = dynamic_cast< const PKCS11_EC_PrivateKey* >(&spec.key()))
+ {
+ return new PKCS11_ECDH_KA_Operation(*key, spec.padding(), use_cofactor);
+ }
+ }
+ catch(...)
+ {
+ }
+
+ return nullptr;
+ }
+
+ PKCS11_ECDH_KA_Operation(const PKCS11_EC_PrivateKey& key, const std::string& kdf, bool use_cofactor)
+ : PK_Ops::Key_Agreement(), m_key(key), m_mechanism(MechanismWrapper::create_ecdh_mechanism(kdf, use_cofactor))
+ {}
+
+
+ /// The encoding in V2.20 was not specified and resulted in different implementations choosing different encodings.
+ /// Applications relying only on a V2.20 encoding (e.g. the DER variant) other than the one specified now (raw) may not work with all V2.30 compliant tokens.
+ secure_vector<byte> agree(size_t key_len, const byte other_key[], size_t other_key_len, const byte salt[],
+ size_t salt_len) override
+ {
+ std::vector<byte> der_encoded_other_key;
+ if(m_key.point_encoding() == PublicPointEncoding::Der)
+ {
+ der_encoded_other_key = DER_Encoder().encode(other_key, other_key_len, OCTET_STRING).get_contents_unlocked();
+ m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size());
+ }
+ else
+ {
+ m_mechanism.set_ecdh_other_key(other_key, other_key_len);
+ }
+
+ if(salt != nullptr && salt_len > 0)
+ {
+ m_mechanism.set_ecdh_salt(salt, salt_len);
+ }
+
+ ObjectHandle secret_handle = 0;
+ AttributeContainer attributes;
+ attributes.add_bool(AttributeType::Sensitive, false);
+ attributes.add_bool(AttributeType::Extractable, true);
+ attributes.add_numeric(AttributeType::Class, static_cast< CK_OBJECT_CLASS >(ObjectClass::SecretKey));
+ attributes.add_numeric(AttributeType::KeyType, static_cast< CK_KEY_TYPE >(KeyType::GenericSecret));
+ attributes.add_numeric(AttributeType::ValueLen, key_len);
+ m_key.module()->C_DeriveKey(m_key.session().handle(), m_mechanism.data(), m_key.handle(), attributes.data(),
+ attributes.count(), &secret_handle);
+
+ Object secret_object(m_key.session(), secret_handle);
+ secure_vector<byte> secret = secret_object.get_attribute_value(AttributeType::Value);
+ if(secret.size() < key_len)
+ {
+ throw PKCS11_Error("ECDH key derivation secret length is too short");
+ }
+ secret.resize(key_len);
+ return secret;
+ }
+
+ private:
+ const PKCS11_EC_PrivateKey& m_key;
+ MechanismWrapper m_mechanism;
+ };
+
+Algo_Registry<PK_Ops::Key_Agreement>::Add g_PKCS11_ECDH_KA_Operation_reg("ECDH",
+ std::bind(&PKCS11_ECDH_KA_Operation::make_ecdh, std::placeholders::_1, false), "pkcs11", BOTAN_PKCS11_ECDH_PRIO);
+
+Algo_Registry<PK_Ops::Key_Agreement>::Add g_PKCS11_ECDHC_KA_Operation_reg("ECDHC",
+ std::bind(&PKCS11_ECDH_KA_Operation::make_ecdh, std::placeholders::_1, true), "pkcs11", BOTAN_PKCS11_ECDH_PRIO);
+
+}
+
+PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::EcKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_ECDH_PublicKey(session, pub_key_handle), PKCS11_ECDH_PrivateKey(session, priv_key_handle));
+ }
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdh.h b/src/lib/prov/pkcs11/p11_ecdh.h
new file mode 100644
index 000000000..9a73be1c5
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdh.h
@@ -0,0 +1,122 @@
+/*
+* PKCS#11 ECDH
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECDH_H__
+#define BOTAN_P11_ECDH_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_ECDH)
+
+#include <botan/p11.h>
+#include <botan/p11_ecc_key.h>
+#include <botan/ecdh.h>
+
+#include <string>
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+class Session;
+
+/// Represents a PKCS#11 ECDH public key
+class BOTAN_DLL PKCS11_ECDH_PublicKey final : public PKCS11_EC_PublicKey
+ {
+ public:
+ /**
+ * Create a PKCS11_ECDH_PublicKey object from an existing PKCS#11 ECDH public key
+ * @param session the session to use
+ * @param handle the handle of the ECDH public key
+ */
+ PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PublicKey(session, handle)
+ {}
+
+ /**
+ * Imports a ECDH public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : PKCS11_EC_PublicKey(session, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDH";
+ }
+
+ /// @return the exported ECDH public key
+ ECDH_PublicKey export_key() const;
+ };
+
+/// Represents a PKCS#11 ECDH private key
+class BOTAN_DLL PKCS11_ECDH_PrivateKey final : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDH_PrivateKey object from an existing PKCS#11 ECDH private key
+ * @param session the session to use
+ * @param handle the handle of the ECDH private key
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PrivateKey(session, handle)
+ {}
+
+ /**
+ * Imports an ECDH private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : PKCS11_EC_PrivateKey(session, props)
+ {}
+
+ /**
+ * Generates a PKCS#11 ECDH private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : PKCS11_EC_PrivateKey(session, ec_params, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDH";
+ }
+
+ inline std::vector<byte> public_value() const override
+ {
+ return unlock(EC2OSP(public_point(), PointGFp::UNCOMPRESSED));
+ }
+
+ /// @return the exported ECDH private key
+ ECDH_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+ };
+
+using PKCS11_ECDH_KeyPair = std::pair<PKCS11_ECDH_PublicKey, PKCS11_ECDH_PrivateKey>;
+
+/**
+* PKCS#11 ECDH key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props the properties of the public key
+* @param priv_props the properties of the private key
+*/
+BOTAN_DLL PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+
+#endif
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.cpp b/src/lib/prov/pkcs11/p11_ecdsa.cpp
new file mode 100644
index 000000000..4aeacda72
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdsa.cpp
@@ -0,0 +1,239 @@
+/*
+* PKCS#11 ECDSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecdsa.h>
+
+#if defined(BOTAN_HAS_ECDSA)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+#include <botan/keypair.h>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#else
+ #include <botan/auto_rng.h>
+#endif
+
+namespace Botan {
+namespace PKCS11 {
+
+ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const
+ {
+ return ECDSA_PublicKey(domain(), public_point());
+ }
+
+bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
+ {
+ if(!public_point().on_the_curve())
+ {
+ return false;
+ }
+
+
+ if(!strong)
+ {
+ return true;
+ }
+
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ }
+
+ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const
+ {
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ System_RNG rng;
+#else
+ AutoSeeded_RNG rng;
+#endif
+ auto priv_key = get_attribute_value(AttributeType::Value);
+
+ return ECDSA_PrivateKey(rng, domain(), BigInt::decode(priv_key));
+ }
+
+secure_vector<byte> PKCS11_ECDSA_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+namespace {
+
+class PKCS11_ECDSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ typedef PKCS11_EC_PrivateKey Key_Type;
+
+ PKCS11_ECDSA_Signature_Operation(const PKCS11_EC_PrivateKey& key, const std::string& emsa)
+ : PK_Ops::Signature(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa))
+ {}
+
+ size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ size_t message_part_size() const override
+ {
+ return m_order.bytes();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast<Byte*>(msg), msg_len);
+ }
+
+ secure_vector<byte> sign(RandomNumberGenerator&) override
+ {
+ secure_vector<byte> signature;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_SignFinal(m_key.session().handle(), signature);
+ }
+ m_initialized = false;
+ return signature;
+ }
+
+ private:
+ const PKCS11_EC_PrivateKey& m_key;
+ const BigInt& m_order;
+ MechanismWrapper m_mechanism;
+ secure_vector<byte> m_first_message;
+ bool m_initialized = false;
+ };
+
+
+class PKCS11_ECDSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ typedef PKCS11_EC_PublicKey Key_Type;
+
+ PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& emsa)
+ : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa))
+ {}
+
+ size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ size_t message_part_size() const override
+ {
+ return m_order.bytes();
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_order.bits();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast<Byte*>(msg), msg_len);
+ }
+
+ bool is_valid_signature(const byte sig[], size_t sig_len) override
+ {
+ ReturnValue return_value = ReturnValue::SignatureInvalid;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), m_first_message.size(),
+ const_cast<Byte*>(sig), sig_len, &return_value);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast<Byte*>(sig), sig_len, &return_value);
+ }
+ m_initialized = false;
+ if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid)
+ {
+ throw PKCS11_ReturnError(return_value);
+ }
+ return return_value == ReturnValue::OK;
+ }
+
+ private:
+ const PKCS11_EC_PublicKey& m_key;
+ const BigInt& m_order;
+ MechanismWrapper m_mechanism;
+ secure_vector<byte> m_first_message;
+ bool m_initialized = false;
+ };
+
+BOTAN_REGISTER_TYPE(PK_Ops::Signature, PKCS11_ECDSA_Signature_Operation, "ECDSA",
+ (make_pk_op<PK_Ops::Signature, PKCS11_ECDSA_Signature_Operation>), "pkcs11", BOTAN_PKCS11_ECDSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Verification, PKCS11_ECDSA_Verification_Operation, "ECDSA",
+ (make_pk_op<PK_Ops::Verification, PKCS11_ECDSA_Verification_Operation>), "pkcs11", BOTAN_PKCS11_ECDSA_PRIO);
+
+}
+
+PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast<CK_MECHANISM_TYPE>(MechanismType::EcKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle), PKCS11_ECDSA_PrivateKey(session,
+ priv_key_handle));
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.h b/src/lib/prov/pkcs11/p11_ecdsa.h
new file mode 100644
index 000000000..2ac59e028
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdsa.h
@@ -0,0 +1,127 @@
+/*
+* PKCS#11 ECDSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECDSA_H__
+#define BOTAN_P11_ECDSA_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_ECDSA)
+
+#include <botan/p11_ecc_key.h>
+#include <botan/ecdsa.h>
+
+#include <string>
+
+namespace Botan {
+namespace PKCS11 {
+class Session;
+
+/// Represents a PKCS#11 ECDSA public key
+class BOTAN_DLL PKCS11_ECDSA_PublicKey final : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDSA_PublicKey object from an existing PKCS#11 ECDSA public key
+ * @param session the session to use
+ * @param handle the handle of the ECDSA public key
+ */
+ PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PublicKey(session, handle)
+ {}
+
+ /**
+ * Imports an ECDSA public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : PKCS11_EC_PublicKey(session, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDSA";
+ }
+
+ inline std::size_t max_input_bits() const override
+ {
+ return domain().get_order().bits();
+ }
+
+ /// @return the exported ECDSA public key
+ ECDSA_PublicKey export_key() const;
+ };
+
+/// Represents a PKCS#11 ECDSA private key
+class BOTAN_DLL PKCS11_ECDSA_PrivateKey final : public PKCS11_EC_PrivateKey
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDSA_PrivateKey object from an existing PKCS#11 ECDSA private key
+ * @param session the session to use
+ * @param handle the handle of the ECDSA private key
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PrivateKey(session, handle)
+ {}
+
+ /**
+ * Imports a ECDSA private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : PKCS11_EC_PrivateKey(session, props)
+ {}
+
+ /**
+ * Generates a PKCS#11 ECDSA private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : PKCS11_EC_PrivateKey(session, ec_params, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDSA";
+ }
+
+ inline size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ /// @return the exported ECDSA private key
+ ECDSA_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+
+ bool check_key(RandomNumberGenerator&, bool) const override;
+ };
+
+using PKCS11_ECDSA_KeyPair = std::pair<PKCS11_ECDSA_PublicKey, PKCS11_ECDSA_PrivateKey>;
+
+/**
+* ECDSA key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props the properties of the public key
+* @param priv_props the properties of the private key
+*/
+BOTAN_DLL PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session,
+ const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+
+#endif
+#endif
diff --git a/src/lib/prov/pkcs11/p11_mechanism.cpp b/src/lib/prov/pkcs11/p11_mechanism.cpp
new file mode 100644
index 000000000..b3cc1c83b
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_mechanism.cpp
@@ -0,0 +1,250 @@
+/*
+* PKCS#11 Mechanism
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/rfc6979.h>
+#include <botan/scan_name.h>
+
+#include <tuple>
+
+namespace Botan {
+namespace PKCS11 {
+
+namespace {
+using PSS_Params = std::tuple<size_t, MechanismType, MGF>;
+
+// maps a PSS mechanism type to the number of bytes used for the salt, the mechanism type of the underlying hash algorithm and the MGF
+static const std::map<MechanismType, PSS_Params> PssOptions =
+ {
+ { MechanismType::RsaPkcsPss, PSS_Params(0, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { MechanismType::Sha1RsaPkcsPss, PSS_Params(20, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { MechanismType::Sha224RsaPkcsPss, PSS_Params(28, MechanismType::Sha224, MGF::Mgf1Sha224) },
+ { MechanismType::Sha256RsaPkcsPss, PSS_Params(32, MechanismType::Sha256, MGF::Mgf1Sha256) },
+ { MechanismType::Sha384RsaPkcsPss, PSS_Params(48, MechanismType::Sha384, MGF::Mgf1Sha384) },
+ { MechanismType::Sha512RsaPkcsPss, PSS_Params(64, MechanismType::Sha512, MGF::Mgf1Sha512) }
+ };
+
+struct MechanismData
+ {
+ explicit MechanismData(MechanismType _type)
+ : type(_type)
+ {}
+
+ virtual ~MechanismData() = default;
+
+ // the mechanism to perform
+ MechanismType type;
+ };
+
+struct RSA_SignMechanism : public MechanismData
+ {
+ explicit RSA_SignMechanism(MechanismType _type)
+ : MechanismData(_type), hash(static_cast<MechanismType>(0)), mgf(static_cast<MGF>(0)), salt_size(0)
+ {
+ auto pss_option = PssOptions.find(type);
+ if(pss_option != PssOptions.end())
+ {
+ hash = std::get<1>(pss_option->second);
+ mgf = std::get<2>(pss_option->second);
+ salt_size = std::get<0>(pss_option->second);
+ }
+ }
+
+ // hash algorithm used in the PSS encoding; if the signature mechanism does not include message hashing,
+ // then this value must be the mechanism used by the application to generate the message hash;
+ // if the signature mechanism includes hashing, then this value must match the hash algorithm indicated by the signature mechanism
+ MechanismType hash;
+
+ // mask generation function to use on the encoded block
+ MGF mgf;
+
+ // length, in bytes, of the salt value used in the PSS encoding; typical values are the length of the message hash and zero
+ size_t salt_size;
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_sign_mechanism`
+static std::map<std::string, RSA_SignMechanism> SignMechanisms =
+ {
+ { "Raw", RSA_SignMechanism(MechanismType::RsaX509) },
+
+ { "EMSA2(Raw)", RSA_SignMechanism(MechanismType::RsaX931) },
+ { "EMSA2(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaX931) },
+
+ // RSASSA PKCS#1 v1.5
+ { "EMSA3(Raw)", RSA_SignMechanism(MechanismType::RsaPkcs) },
+ { "EMSA3(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) },
+ { "EMSA3(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) },
+ { "EMSA3(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) },
+ { "EMSA3(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) },
+ { "EMSA3(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) },
+
+ // RSASSA PKCS#1 PSS
+ { "EMSA4(Raw)", RSA_SignMechanism(MechanismType::RsaPkcsPss) },
+ { "EMSA4(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcsPss) },
+ { "EMSA4(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcsPss) },
+ { "EMSA4(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) },
+ { "EMSA4(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) },
+ { "EMSA4(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) },
+
+ { "ISO9796", RSA_SignMechanism(MechanismType::Rsa9796) }
+ };
+
+struct RSA_CryptMechanism : public MechanismData
+ {
+ RSA_CryptMechanism(MechanismType _type, size_t _padding_size, MechanismType _hash, MGF _mgf)
+ : MechanismData(_type), hash(_hash), mgf(_mgf), padding_size(_padding_size)
+ {}
+
+ RSA_CryptMechanism(MechanismType _type, size_t _padding_size)
+ : RSA_CryptMechanism(_type, _padding_size, static_cast<MechanismType>(0), static_cast<MGF>(0))
+ {}
+
+ // mechanism ID of the message digest algorithm used to calculate the digest of the encoding parameter
+ MechanismType hash;
+
+ // mask generation function to use on the encoded block
+ MGF mgf;
+
+ // number of bytes required for the padding
+ size_t padding_size;
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_crypt_mechanism`
+static const std::map<std::string, RSA_CryptMechanism> CryptMechanisms =
+ {
+ { "Raw", RSA_CryptMechanism(MechanismType::RsaX509, 0) },
+ { "EME-PKCS1-v1_5", RSA_CryptMechanism(MechanismType::RsaPkcs, 11) },
+ { "OAEP(SHA-1)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 20, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { "OAEP(SHA-224)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 28, MechanismType::Sha224, MGF::Mgf1Sha224) },
+ { "OAEP(SHA-256)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 32, MechanismType::Sha256, MGF::Mgf1Sha256) },
+ { "OAEP(SHA-384)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 48, MechanismType::Sha384, MGF::Mgf1Sha384) },
+ { "OAEP(SHA-512)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 64, MechanismType::Sha512, MGF::Mgf1Sha512) }
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdsa_mechanism`
+static std::map<std::string, MechanismType> EcdsaHash =
+ {
+ { "Raw", MechanismType::Ecdsa },
+ { "SHA-160", MechanismType::EcdsaSha1 },
+ { "SHA-224", MechanismType::EcdsaSha224 },
+ { "SHA-256", MechanismType::EcdsaSha256 },
+ { "SHA-384", MechanismType::EcdsaSha384 },
+ { "SHA-512", MechanismType::EcdsaSha512 }
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdh_mechanism`
+static std::map<std::string, KeyDerivation> EcdhHash =
+ {
+ { "Raw", KeyDerivation::Null },
+ { "SHA-160", KeyDerivation::Sha1Kdf },
+ { "SHA-224", KeyDerivation::Sha224Kdf },
+ { "SHA-256", KeyDerivation::Sha256Kdf },
+ { "SHA-384", KeyDerivation::Sha384Kdf },
+ { "SHA-512", KeyDerivation::Sha512Kdf }
+ };
+}
+
+MechanismWrapper::MechanismWrapper(MechanismType mechanism_type)
+ : m_mechanism( { static_cast<CK_MECHANISM_TYPE>(mechanism_type), nullptr, 0 }), m_parameters(nullptr)
+ {}
+
+MechanismWrapper MechanismWrapper::create_rsa_crypt_mechanism(const std::string& padding)
+ {
+ auto mechanism_info_it = CryptMechanisms.find(padding);
+ if(mechanism_info_it == CryptMechanisms.end())
+ {
+ // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
+ throw Lookup_Error("PKCS#11 RSA encrypt/decrypt does not support EME " + padding);
+ }
+ RSA_CryptMechanism mechanism_info = mechanism_info_it->second;
+
+ MechanismWrapper mech(mechanism_info.type);
+ if(mechanism_info.type == MechanismType::RsaPkcsOaep)
+ {
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->oaep_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash);
+ mech.m_parameters->oaep_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf);
+ mech.m_parameters->oaep_params.source = CKZ_DATA_SPECIFIED;
+ mech.m_parameters->oaep_params.pSourceData = nullptr;
+ mech.m_parameters->oaep_params.ulSourceDataLen = 0;
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsOaepParams);
+ }
+ mech.m_padding_size = mechanism_info.padding_size;
+ return mech;
+ }
+
+MechanismWrapper MechanismWrapper::create_rsa_sign_mechanism(const std::string& padding)
+ {
+ auto mechanism_info_it = SignMechanisms.find(padding);
+ if(mechanism_info_it == SignMechanisms.end())
+ {
+ // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
+ throw Lookup_Error("PKCS#11 RSA sign/verify does not support EMSA " + padding);
+ }
+ RSA_SignMechanism mechanism_info = mechanism_info_it->second;
+
+ MechanismWrapper mech(mechanism_info.type);
+ if(PssOptions.find(mechanism_info.type) != PssOptions.end())
+ {
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->pss_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash);
+ mech.m_parameters->pss_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf);
+ mech.m_parameters->pss_params.sLen = mechanism_info.salt_size;
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsPssParams);
+ }
+ return mech;
+ }
+
+MechanismWrapper MechanismWrapper::create_ecdsa_mechanism(const std::string& hash)
+ {
+ std::string hash_name = hash;
+
+ if(hash_name != "Raw")
+ {
+ hash_name = hash_for_deterministic_signature(hash);
+ }
+
+ auto mechanism_type = EcdsaHash.find(hash_name);
+ if(mechanism_type == EcdsaHash.end())
+ {
+ throw Lookup_Error("PKCS#11 ECDSA sign/verify does not support " + hash);
+ }
+ return MechanismWrapper(mechanism_type->second);
+ }
+
+MechanismWrapper MechanismWrapper::create_ecdh_mechanism(const std::string& kdf_name, bool use_cofactor)
+ {
+ std::string hash = kdf_name;
+
+ if(kdf_name != "Raw")
+ {
+ SCAN_Name kdf_hash(kdf_name);
+
+ if(kdf_hash.arg_count() > 0)
+ {
+ hash = kdf_hash.arg(0);
+ }
+ }
+
+ auto kdf = EcdhHash.find(hash);
+ if(kdf == EcdhHash.end())
+ {
+ throw Lookup_Error("PKCS#11 ECDH key derivation does not support KDF " + kdf_name);
+ }
+ MechanismWrapper mech(use_cofactor ? MechanismType::Ecdh1CofactorDerive : MechanismType::Ecdh1Derive);
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->ecdh_params.kdf = static_cast<CK_EC_KDF_TYPE>(kdf->second);
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(Ecdh1DeriveParams);
+ return mech;
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_mechanism.h b/src/lib/prov/pkcs11/p11_mechanism.h
new file mode 100644
index 000000000..5d8c826ee
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_mechanism.h
@@ -0,0 +1,108 @@
+/*
+* PKCS#11 Mechanism
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_MECHANISM_H__
+#define BOTAN_P11_MECHANISM_H__
+
+#include <botan/p11.h>
+
+#include <utility>
+#include <string>
+#include <memory>
+
+namespace Botan {
+namespace PKCS11 {
+
+/**
+* Simple class to build and hold the data for a CK_MECHANISM struct
+* for RSA (encryption/decryption, signature/verification)
+* and EC (ecdsa signature/verification, ecdh key derivation)
+*/
+class MechanismWrapper final
+ {
+ public:
+ /// @param mechanism_type the CK_MECHANISM_TYPE for the `mechanism` field of the CK_MECHANISM struct
+ explicit MechanismWrapper(MechanismType mechanism_type);
+
+ /**
+ * Creates the CK_MECHANISM data for RSA encryption/decryption
+ * @param padding supported paddings are Raw (X.509), EME-PKCS1-v1_5 (PKCS#1 v1.5) and OAEP (PKCS#1 OAEP)
+ */
+ static MechanismWrapper create_rsa_crypt_mechanism(const std::string& padding);
+
+ /**
+ * Creates the CK_MECHANISM data for RSA signature/verification
+ * @param padding supported paddings are Raw (X.509), EMSA3 (PKCS#1 v1.5), EMSA4 (PKCS#1 PSS),
+ * EMSA2 (ANSI X9.31) and ISO9796 (ISO/IEC 9796)
+ */
+ static MechanismWrapper create_rsa_sign_mechanism(const std::string& padding);
+
+ /**
+ * Creates the CK_MECHANISM data for ECDSA signature/verification
+ * @param hash the hash algorithm used to hash the data to sign.
+ * supported hash functions are Raw and SHA-160 to SHA-512
+ */
+ static MechanismWrapper create_ecdsa_mechanism(const std::string& hash);
+
+ /**
+ * Creates the CK_MECHANISM data for ECDH key derivation (CKM_ECDH1_DERIVE or CKM_ECDH1_COFACTOR_DERIVE)
+ * @param kdf_name the key derivation function to use. Supported KDFs are Raw and SHA-160 to SHA-512
+ * @param use_cofactor true if the cofactor key derivation mechanism should be used
+ */
+ static MechanismWrapper create_ecdh_mechanism(const std::string& kdf_name, bool use_cofactor);
+
+ /// Sets the salt for the ECDH mechanism parameters
+ inline void set_ecdh_salt(const byte salt[], size_t salt_len)
+ {
+ m_parameters->ecdh_params.pSharedData = const_cast<byte*>(salt);
+ m_parameters->ecdh_params.ulSharedDataLen = salt_len;
+ }
+
+ /// Sets the public key of the other party for the ECDH mechanism parameters
+ inline void set_ecdh_other_key(const byte other_key[], size_t other_key_len)
+ {
+ m_parameters->ecdh_params.pPublicData = const_cast<byte*>(other_key);
+ m_parameters->ecdh_params.ulPublicDataLen = other_key_len;
+ }
+
+ /// @return a pointer to the CK_MECHANISM struct that can be passed to the cryptoki functions
+ inline Mechanism* data() const
+ {
+ return const_cast<Mechanism*>(&m_mechanism);
+ }
+
+ /// @return the size of the padding in bytes (for encryption/decryption)
+ inline size_t padding_size() const
+ {
+ return m_padding_size;
+ }
+
+ /// Holds the mechanism parameters for OEAP, PSS and ECDH
+ union MechanismParameters
+ {
+ MechanismParameters()
+ {
+ std::memset(this, 0, sizeof(MechanismParameters));
+ }
+
+ RsaPkcsOaepParams oaep_params;
+ RsaPkcsPssParams pss_params;
+ Ecdh1DeriveParams ecdh_params;
+ };
+
+ private:
+ Mechanism m_mechanism;
+ std::shared_ptr<MechanismParameters> m_parameters;
+ size_t m_padding_size = 0;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_module.cpp b/src/lib/prov/pkcs11/p11_module.cpp
new file mode 100644
index 000000000..4ea3dc56d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_module.cpp
@@ -0,0 +1,41 @@
+/*
+* PKCS#11 Module
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_module.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+Module::Module(const std::string& file_path, C_InitializeArgs init_args)
+ : m_file_path(file_path)
+ {
+ reload(init_args);
+ }
+
+Module::~Module() BOTAN_NOEXCEPT
+ {
+ m_low_level->C_Finalize(nullptr, nullptr);
+ }
+
+void Module::reload(C_InitializeArgs init_args)
+ {
+ if(m_low_level)
+ {
+ m_low_level->C_Finalize(nullptr);
+ }
+
+ m_library.reset(new Dynamically_Loaded_Library(m_file_path));
+ LowLevel::C_GetFunctionList(*m_library, &m_func_list);
+ m_low_level.reset(new LowLevel(m_func_list));
+
+ m_low_level->C_Initialize(&init_args);
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_module.h b/src/lib/prov/pkcs11/p11_module.h
new file mode 100644
index 000000000..990458a4d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_module.h
@@ -0,0 +1,79 @@
+/*
+* PKCS#11 Module
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_MODULE_H__
+#define BOTAN_P11_MODULE_H__
+
+#include <string>
+#include <memory>
+
+#include <botan/p11.h>
+#include <botan/dyn_load.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+/**
+* Loads the PKCS#11 shared library
+* Calls C_Initialize on load and C_Finalize on destruction
+*/
+class BOTAN_DLL Module final
+ {
+ public:
+ /**
+ * Loads the shared library and calls C_Initialize
+ * @param file_path the path to the PKCS#11 shared library
+ * @param init_args flags to use for `C_Initialize`
+ */
+ Module(const std::string& file_path, C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr });
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ Module(Module&& other) = default;
+ Module& operator=(Module&& other) = default;
+#endif
+
+ // Dtor calls C_Finalize(). A copy could be deleted while the origin still exists
+ // Furthermore std::unique_ptr member -> not copyable
+ Module(const Module& other) = delete;
+ Module& operator=(const Module& other) = delete;
+
+ /// Calls C_Finalize()
+ ~Module() BOTAN_NOEXCEPT;
+
+ /**
+ * Reloads the module and reinitializes it
+ * @param init_args flags to use for `C_Initialize`
+ */
+ void reload(C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr });
+
+ inline LowLevel* operator->() const
+ {
+ return m_low_level.get();
+ }
+
+ /// @return general information about Cryptoki
+ inline Info get_info() const
+ {
+ Info info;
+ m_low_level->C_GetInfo(&info);
+ return info;
+ }
+
+ private:
+ const std::string m_file_path;
+ FunctionListPtr m_func_list = nullptr;
+ std::unique_ptr<Dynamically_Loaded_Library> m_library = nullptr;
+ std::unique_ptr<LowLevel> m_low_level = nullptr;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_object.cpp b/src/lib/prov/pkcs11/p11_object.cpp
new file mode 100644
index 000000000..ef7477284
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_object.cpp
@@ -0,0 +1,217 @@
+/*
+* PKCS#11 Object
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_object.h>
+
+#include <map>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+AttributeContainer::AttributeContainer(ObjectClass object_class)
+ {
+ add_class(object_class);
+ }
+
+void AttributeContainer::add_class(ObjectClass object_class)
+ {
+ m_numerics.push_back(static_cast< uint64_t >(object_class));
+ add_attribute(AttributeType::Class, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(ObjectClass));
+ }
+
+void AttributeContainer::add_string(AttributeType attribute, const std::string& value)
+ {
+ m_strings.push_back(value);
+ add_attribute(attribute, reinterpret_cast< const byte* >(m_strings.back().data()), value.size());
+ }
+
+void AttributeContainer::add_binary(AttributeType attribute, const byte* value, size_t length)
+ {
+ m_vectors.push_back(secure_vector<byte>(value, value + length));
+ add_attribute(attribute, reinterpret_cast< const byte* >(m_vectors.back().data()), length);
+ }
+
+void AttributeContainer::add_bool(AttributeType attribute, bool value)
+ {
+ m_numerics.push_back(value ? True : False);
+ add_attribute(attribute, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(Bbool));
+ }
+
+void AttributeContainer::add_attribute(AttributeType attribute, const byte* value, uint32_t size)
+ {
+ bool exists = false;
+ // check if the attribute has been added already
+ for(auto& existing_attribute : m_attributes)
+ {
+ if(existing_attribute.type == static_cast< CK_ATTRIBUTE_TYPE >(attribute))
+ {
+ // remove old entries
+ m_strings.erase(std::remove_if(m_strings.begin(), m_strings.end(), [ &existing_attribute ](const std::string& data)
+ {
+ return data.data() == existing_attribute.pValue;
+ }), m_strings.end());
+
+ m_numerics.erase(std::remove_if(m_numerics.begin(), m_numerics.end(), [ &existing_attribute ](const uint64_t& data)
+ {
+ return &data == existing_attribute.pValue;
+ }), m_numerics.end());
+
+ m_vectors.erase(std::remove_if(m_vectors.begin(),
+ m_vectors.end(), [ &existing_attribute ](const secure_vector<byte>& data)
+ {
+ return data.data() == existing_attribute.pValue;
+ }), m_vectors.end());
+
+ existing_attribute.pValue = const_cast< byte* >(value);
+ existing_attribute.ulValueLen = size;
+ exists = true;
+ break;
+ }
+ }
+
+ if(!exists)
+ {
+ m_attributes.push_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(attribute), const_cast< byte* >(value), size });
+ }
+ }
+
+// ====================================================================================================
+
+ObjectFinder::ObjectFinder(Session& session, const std::vector<Attribute>& search_template)
+ : m_session(session), m_search_terminated(false)
+ {
+ module()->C_FindObjectsInit(m_session.get().handle(), const_cast< Attribute* >(search_template.data()),
+ search_template.size());
+ }
+
+ObjectFinder::~ObjectFinder() BOTAN_NOEXCEPT
+ {
+ if(m_search_terminated == false)
+ {
+ module()->C_FindObjectsFinal(m_session.get().handle(), nullptr);
+ }
+ }
+
+std::vector<ObjectHandle> ObjectFinder::find(uint32_t max_count) const
+ {
+ std::vector<ObjectHandle> result(max_count);
+ Ulong objectCount = 0;
+ module()->C_FindObjects(m_session.get().handle(), result.data(), max_count, &objectCount);
+ if(objectCount < max_count)
+ {
+ result.resize(objectCount);
+ }
+ return result;
+ }
+
+void ObjectFinder::finish()
+ {
+ module()->C_FindObjectsFinal(m_session.get().handle());
+ m_search_terminated = true;
+ }
+
+// ====================================================================================================
+
+ObjectProperties::ObjectProperties(ObjectClass object_class)
+ : AttributeContainer(object_class), m_object_class(object_class)
+ {}
+
+// ====================================================================================================
+
+StorageObjectProperties::StorageObjectProperties(ObjectClass object_class)
+ : ObjectProperties(object_class)
+ {}
+
+// ====================================================================================================
+
+DataObjectProperties::DataObjectProperties()
+ : StorageObjectProperties(ObjectClass::Data)
+ {}
+
+// ====================================================================================================
+
+CertificateProperties::CertificateProperties(CertificateType cert_type)
+ : StorageObjectProperties(ObjectClass::Certificate), m_cert_type(cert_type)
+ {
+ add_numeric(AttributeType::CertificateType, static_cast< CK_CERTIFICATE_TYPE >(m_cert_type));
+ }
+
+// ====================================================================================================
+
+KeyProperties::KeyProperties(ObjectClass object_class, KeyType key_type)
+ : StorageObjectProperties(object_class), m_key_type(key_type)
+ {
+ add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type));
+ }
+
+// ====================================================================================================
+
+PublicKeyProperties::PublicKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::PublicKey, key_type)
+ {}
+
+// ====================================================================================================
+
+PrivateKeyProperties::PrivateKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::PrivateKey, key_type)
+ {}
+
+// ====================================================================================================
+
+SecretKeyProperties::SecretKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::SecretKey, key_type)
+ {}
+
+// ====================================================================================================
+
+DomainParameterProperties::DomainParameterProperties(KeyType key_type)
+ : StorageObjectProperties(ObjectClass::DomainParameters), m_key_type(key_type)
+ {
+ add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type));
+ }
+
+// ====================================================================================================
+
+Object::Object(Session& session, ObjectHandle handle)
+ : m_session(session), m_handle(handle)
+ {}
+
+Object::Object(Session& session, const ObjectProperties& obj_props)
+ : m_session(session), m_handle(0)
+ {
+ m_session.get().module()->C_CreateObject(m_session.get().handle(), obj_props.data(), obj_props.count(), &m_handle);
+ }
+
+secure_vector<byte> Object::get_attribute_value(AttributeType attribute) const
+ {
+ std::map<AttributeType, secure_vector<byte>> attribute_map = { { attribute, secure_vector<byte>() } };
+ module()->C_GetAttributeValue(m_session.get().handle(), m_handle, attribute_map);
+ return attribute_map.at(attribute);
+ }
+
+void Object::set_attribute_value(AttributeType attribute, const secure_vector<byte>& value) const
+ {
+ std::map<AttributeType, secure_vector<byte>> attribute_map = { { attribute, value } };
+ module()->C_SetAttributeValue(m_session.get().handle(), m_handle, attribute_map);
+ }
+
+void Object::destroy() const
+ {
+ module()->C_DestroyObject(m_session.get().handle(), m_handle);
+ }
+
+ObjectHandle Object::copy(const AttributeContainer& modified_attributes) const
+ {
+ ObjectHandle copied_handle;
+ module()->C_CopyObject(m_session.get().handle(), m_handle, modified_attributes.data(), modified_attributes.count(),
+ &copied_handle);
+ return copied_handle;
+ }
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_object.h b/src/lib/prov/pkcs11/p11_object.h
new file mode 100644
index 000000000..4a6a54b20
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_object.h
@@ -0,0 +1,743 @@
+/*
+* PKCS#11 Object
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_OBJECT_H__
+#define BOTAN_P11_OBJECT_H__
+
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+#include <botan/secmem.h>
+
+#include <vector>
+#include <string>
+#include <type_traits>
+#include <list>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Module;
+
+/// Helper class to build the Attribute / CK_ATTRIBUTE structures
+class BOTAN_DLL AttributeContainer
+ {
+ public:
+ AttributeContainer() = default;
+
+ /// @param object_class the class type of this container
+ AttributeContainer(ObjectClass object_class);
+
+ virtual ~AttributeContainer() = default;
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ AttributeContainer(AttributeContainer&& other) = default;
+ AttributeContainer& operator=(AttributeContainer&& other) = default;
+#endif
+
+ // Warning when implementing copy/assignment: m_attributes contains pointers to the other members which must be updated after a copy
+ AttributeContainer(const AttributeContainer& other) = delete;
+ AttributeContainer& operator=(const AttributeContainer& other) = delete;
+
+ /// @return the attributes this container contains
+ inline const std::vector<Attribute>& attributes() const
+ {
+ return m_attributes;
+ }
+
+ inline Attribute* data() const
+ {
+ return const_cast< Attribute* >(m_attributes.data());
+ }
+
+ /// @return the number of attributes in this container
+ inline size_t count() const
+ {
+ return m_attributes.size();
+ }
+
+ /// Add a class attribute (CKA_CLASS / AttributeType::Class)
+ void add_class(ObjectClass object_class);
+
+ /// Add a string attribute (e.g. CKA_LABEL / AttributeType::Label)
+ void add_string(AttributeType attribute, const std::string& value);
+
+ /// Add a binary attribute (e.g. CKA_ID / AttributeType::Id)
+ void add_binary(AttributeType attribute, const byte* value, size_t length);
+
+ /// Add a binary attribute (e.g. CKA_ID / AttributeType::Id)
+ template<typename TAlloc>
+ void add_binary(AttributeType attribute, const std::vector<byte, TAlloc>& binary)
+ {
+ add_binary(attribute, binary.data(), binary.size());
+ }
+
+ /// Add a bool attribute (e.g. CKA_SENSITIVE / AttributeType::Sensitive)
+ void add_bool(AttributeType attribute, bool value);
+
+ /// Add a numeric attribute (e.g. CKA_MODULUS_BITS / AttributeType::ModulusBits)
+ template<typename T>
+ void add_numeric(AttributeType attribute, T value)
+ {
+ static_assert(std::is_integral<T>::value, "Numeric value required.");
+ m_numerics.push_back(static_cast< uint64_t >(value));
+ add_attribute(attribute, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(T));
+ }
+
+ protected:
+ /// Add a attribute with the given value and size to the attribute collection `m_attributes`
+ void add_attribute(AttributeType attribute, const byte* value, uint32_t size);
+
+ private:
+ std::vector<Attribute> m_attributes;
+ std::list<uint64_t> m_numerics;
+ std::list<std::string> m_strings;
+ std::list<secure_vector<byte>> m_vectors;
+ };
+
+/// Manages calls to C_FindObjects* functions (C_FindObjectsInit -> C_FindObjects -> C_FindObjectsFinal)
+class BOTAN_DLL ObjectFinder final
+ {
+ public:
+ /**
+ * Initializes a search for token and session objects that match a template (calls C_FindObjectsInit)
+ * @param session the session to use for the search
+ * @param search_template the search_template as a vector of `Attribute`
+ */
+ ObjectFinder(Session& session, const std::vector<Attribute>& search_template);
+
+ ObjectFinder(const ObjectFinder& other) = default;
+ ObjectFinder& operator=(const ObjectFinder& other) = default;
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ ObjectFinder(ObjectFinder&& other) = default;
+ ObjectFinder& operator=(ObjectFinder&& other) = default;
+#endif
+
+ /// Terminates a search for token and session objects (calls C_FindObjectsFinal)
+ ~ObjectFinder() BOTAN_NOEXCEPT;
+
+ /**
+ * Starts or continues a search for token and session objects that match a template, obtaining additional object handles (calls C_FindObjects)
+ * @param max_count maximum amount of object handles to retrieve. Default = 100
+ * @return the result of the search as a vector of `ObjectHandle`
+ */
+ std::vector<ObjectHandle> find(std::uint32_t max_count = 100) const;
+
+ /// Finishes the search operation manually to allow a new ObjectFinder to exist
+ void finish();
+
+ /// @return the module this `ObjectFinder` belongs to
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+
+ private:
+ const std::reference_wrapper<Session> m_session;
+ bool m_search_terminated;
+ };
+
+/// Common attributes of all objects
+class BOTAN_DLL ObjectProperties : public AttributeContainer
+ {
+ public:
+ /// @param object_class the object class of the object
+ ObjectProperties(ObjectClass object_class);
+
+ /// @return the object class of this object
+ inline ObjectClass object_class() const
+ {
+ return m_object_class;
+ }
+
+ private:
+ const ObjectClass m_object_class;
+ };
+
+/// Common attributes of all storage objects
+class BOTAN_DLL StorageObjectProperties : public ObjectProperties
+ {
+ public:
+ /// @param object_class the CK_OBJECT_CLASS this storage object belongs to
+ StorageObjectProperties(ObjectClass object_class);
+
+ /// @param label description of the object (RFC2279 string)
+ inline void set_label(const std::string& label)
+ {
+ add_string(AttributeType::Label, label);
+ }
+
+ /// @param value if true the object is a token object; otherwise the object is a session object
+ inline void set_token(bool value)
+ {
+ add_bool(AttributeType::Token, value);
+ }
+
+ /**
+ * @param value if true the object is a private object; otherwise the object is a public object
+ * When private, a user may not access the object until the user has been authenticated to the token
+ */
+ inline void set_private(bool value)
+ {
+ add_bool(AttributeType::Private, value);
+ }
+
+ /// @param value if true the object can be modified, otherwise it is read-only
+ void set_modifiable(bool value)
+ {
+ add_bool(AttributeType::Modifiable, value);
+ }
+
+ /// @param value if true the object can be copied using C_CopyObject
+ void set_copyable(bool value)
+ {
+ add_bool(AttributeType::Copyable, value);
+ }
+
+ /// @param value if true the object can be destroyed using C_DestroyObject
+ void set_destroyable(bool value)
+ {
+ add_bool(AttributeType::Destroyable, value);
+ }
+ };
+
+/// Common attributes of all data objects
+class BOTAN_DLL DataObjectProperties : public StorageObjectProperties
+ {
+ public:
+ DataObjectProperties();
+
+ /// @param value description of the application that manages the object (RFC2279 string)
+ inline void set_application(const std::string& value)
+ {
+ add_string(AttributeType::Application, value);
+ }
+
+ /// @param object_id DER-encoding of the object identifier indicating the data object type
+ inline void set_object_id(const std::vector<byte>& object_id)
+ {
+ add_binary(AttributeType::ObjectId, object_id);
+ }
+
+ /// @param value value of the object
+ inline void set_value(const secure_vector<byte>& value)
+ {
+ add_binary(AttributeType::Value, value);
+ }
+ };
+
+/// Common attributes of all certificate objects
+class BOTAN_DLL CertificateProperties : public StorageObjectProperties
+ {
+ public:
+ /// @param cert_type type of certificate
+ CertificateProperties(CertificateType cert_type);
+
+ /// @param value the certificate can be trusted for the application that it was created (can only be set to true by SO user)
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /// @param category one of `CertificateCategory`
+ inline void set_category(CertificateCategory category)
+ {
+ add_numeric(AttributeType::CertificateCategory, static_cast< CK_CERTIFICATE_CATEGORY >(category));
+ }
+
+ /**
+ * @param checksum the value of this attribute is derived from the certificate by taking the
+ * first three bytes of the SHA - 1 hash of the certificate object�s `CKA_VALUE` attribute
+ */
+ inline void set_check_value(const std::vector<byte>& checksum)
+ {
+ add_binary(AttributeType::CheckValue, checksum);
+ }
+
+ /// @param date start date for the certificate
+ inline void set_start_date(Date date)
+ {
+ add_binary(AttributeType::StartDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param date end date for the certificate
+ inline void set_end_date(Date date)
+ {
+ add_binary(AttributeType::EndDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for the public key contained in this certificate
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+
+ /// @return the certificate type of this certificate object
+ inline CertificateType cert_type() const
+ {
+ return m_cert_type;
+ }
+
+ private:
+ const CertificateType m_cert_type;
+ };
+
+/// Common attributes of all key objects
+class BOTAN_DLL KeyProperties : public StorageObjectProperties
+ {
+ public:
+ /**
+ * @param object_class the `CK_OBJECT_CLASS` this key object belongs to
+ * @param key_type type of key
+ */
+ KeyProperties(ObjectClass object_class, KeyType key_type);
+
+ /// @param id key identifier for key
+ inline void set_id(const std::vector<byte>& id)
+ {
+ add_binary(AttributeType::Id, id);
+ }
+
+ /// @param date start date for the key
+ inline void set_start_date(Date date)
+ {
+ add_binary(AttributeType::StartDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param date end date for the key
+ inline void set_end_date(Date date)
+ {
+ add_binary(AttributeType::EndDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param value true if key supports key derivation (i.e., if other keys can be derived from this one)
+ inline void set_derive(bool value)
+ {
+ add_bool(AttributeType::Derive, value);
+ }
+
+ /**
+ * Sets a list of mechanisms allowed to be used with this key
+ * Not implemented
+ */
+ inline void set_allowed_mechanisms(const std::vector<MechanismType>&)
+ {
+ throw Exception("Not implemented (KeyProperties::set_allowed_mechanisms)");
+ }
+
+ /// @return the key type of this key object
+ inline KeyType key_type() const
+ {
+ return m_key_type;
+ }
+
+ private:
+ const KeyType m_key_type;
+ };
+
+/// Common attributes of all public key objects
+class BOTAN_DLL PublicKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ PublicKeyProperties(KeyType key_type);
+
+ /// @param subject DER-encoding of the key subject name
+ inline void set_subject(const std::vector<byte>& subject)
+ {
+ add_binary(AttributeType::Subject, subject);
+ }
+
+ /// @param value true if the key supports encryption
+ inline void set_encrypt(bool value)
+ {
+ add_bool(AttributeType::Encrypt, value);
+ }
+
+ /// @param value true if the key supports verification where the signature is an appendix to the data
+ inline void set_verify(bool value)
+ {
+ add_bool(AttributeType::Verify, value);
+ }
+
+ /// @param value true if the key supports verification where the data is recovered from the signature
+ inline void set_verify_recover(bool value)
+ {
+ add_bool(AttributeType::VerifyRecover, value);
+ }
+
+ /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys)
+ inline void set_wrap(bool value)
+ {
+ add_bool(AttributeType::Wrap, value);
+ }
+
+ /**
+ * @param value true if the key can be trusted for the application that it was created.
+ * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE`
+ */
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to match against any keys wrapped using this wrapping key.
+ * Keys that do not match cannot be wrapped
+ * Not implemented
+ */
+ inline void set_wrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (PublicKeyProperties::set_wrap_template)");
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+ };
+
+/// Common attributes of all private keys
+class BOTAN_DLL PrivateKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ PrivateKeyProperties(KeyType key_type);
+
+ /// @param subject DER-encoding of the key subject name
+ inline void set_subject(const std::vector<byte>& subject)
+ {
+ add_binary(AttributeType::Subject, subject);
+ }
+
+ /// @param value true if the key is sensitive
+ inline void set_sensitive(bool value)
+ {
+ add_bool(AttributeType::Sensitive, value);
+ }
+
+ /// @param value true if the key supports decryption
+ inline void set_decrypt(bool value)
+ {
+ add_bool(AttributeType::Decrypt, value);
+ }
+
+ /// @param value true if the key supports signatures where the signature is an appendix to the data
+ inline void set_sign(bool value)
+ {
+ add_bool(AttributeType::Sign, value);
+ }
+
+ /// @param value true if the key supports signatures where the data can be recovered from the signature
+ inline void set_sign_recover(bool value)
+ {
+ add_bool(AttributeType::SignRecover, value);
+ }
+
+ /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys)
+ inline void set_unwrap(bool value)
+ {
+ add_bool(AttributeType::Unwrap, value);
+ }
+
+ /// @param value true if the key is extractable and can be wrapped
+ inline void set_extractable(bool value)
+ {
+ add_bool(AttributeType::Extractable, value);
+ }
+
+ /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE`
+ inline void set_wrap_with_trusted(bool value)
+ {
+ add_bool(AttributeType::WrapWithTrusted, value);
+ }
+
+ /// @param value If true, the user has to supply the PIN for each use (sign or decrypt) with the key
+ inline void set_always_authenticate(bool value)
+ {
+ add_bool(AttributeType::AlwaysAuthenticate, value);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to apply to any keys unwrapped using this wrapping key.
+ * Any user supplied template is applied after this template as if the object has already been created
+ * Not implemented
+ */
+ inline void set_unwrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (PrivateKeyProperties::set_unwrap_template)");
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+ };
+
+/// Common attributes of all secret (symmetric) keys
+class BOTAN_DLL SecretKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ SecretKeyProperties(KeyType key_type);
+
+ /// @param value true if the key is sensitive
+ inline void set_sensitive(bool value)
+ {
+ add_bool(AttributeType::Sensitive, value);
+ }
+
+ /// @param value true if the key supports encryption
+ inline void set_encrypt(bool value)
+ {
+ add_bool(AttributeType::Encrypt, value);
+ }
+
+ /// @param value true if the key supports decryption
+ inline void set_decrypt(bool value)
+ {
+ add_bool(AttributeType::Decrypt, value);
+ }
+
+ /// @param value true if the key supports signatures where the signature is an appendix to the data
+ inline void set_sign(bool value)
+ {
+ add_bool(AttributeType::Sign, value);
+ }
+
+ /// @param value true if the key supports verification where the signature is an appendix to the data
+ inline void set_verify(bool value)
+ {
+ add_bool(AttributeType::Verify, value);
+ }
+
+ /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys)
+ inline void set_unwrap(bool value)
+ {
+ add_bool(AttributeType::Unwrap, value);
+ }
+
+ /// @param value true if the key is extractable and can be wrapped
+ inline void set_extractable(bool value)
+ {
+ add_bool(AttributeType::Extractable, value);
+ }
+
+ /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE`
+ inline void set_wrap_with_trusted(bool value)
+ {
+ add_bool(AttributeType::WrapWithTrusted, value);
+ }
+
+ /// @param value if true, the user has to supply the PIN for each use (sign or decrypt) with the key
+ inline void set_always_authenticate(bool value)
+ {
+ add_bool(AttributeType::AlwaysAuthenticate, value);
+ }
+
+ /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys)
+ inline void set_wrap(bool value)
+ {
+ add_bool(AttributeType::Wrap, value);
+ }
+
+ /**
+ * @param value the key can be trusted for the application that it was created.
+ * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE`
+ */
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /// @param checksum the key check value of this key
+ inline void set_check_value(const std::vector<byte>& checksum)
+ {
+ add_binary(AttributeType::CheckValue, checksum);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to match against any keys wrapped using this wrapping key.
+ * Keys that do not match cannot be wrapped
+ * Not implemented
+ */
+ inline void set_wrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (SecretKeyProperties::set_wrap_template)");
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to apply to any keys unwrapped using this wrapping key
+ * Any user supplied template is applied after this template as if the object has already been created
+ * Not Implemented
+ */
+ inline void set_unwrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (SecretKeyProperties::set_unwrap_template)");
+ }
+ };
+
+/// Common attributes of domain parameter
+class BOTAN_DLL DomainParameterProperties : public StorageObjectProperties
+ {
+ public:
+ /// @param key_type type of key the domain parameters can be used to generate
+ DomainParameterProperties(KeyType key_type);
+
+ /// @return the key type
+ inline KeyType key_type() const
+ {
+ return m_key_type;
+ }
+
+ private:
+ const KeyType m_key_type;
+ };
+
+class BOTAN_DLL Object
+ {
+ public:
+ /**
+ * Creates an `Object` from an existing PKCS#11 object
+ * @param session the session the object belongs to
+ * @param handle handle of the object
+ */
+
+ Object(Session& session, ObjectHandle handle);
+
+ /**
+ * Creates the object
+ * @param session the session in which the object should be created
+ * @param obj_props properties of this object
+ */
+ Object(Session& session, const ObjectProperties& obj_props);
+
+ virtual ~Object() = default;
+
+ /// Searches for all objects of the given type that match `search_template`
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::vector<Attribute>& search_template);
+
+ /// Searches for all objects of the given type using the label (`CKA_LABEL`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::string& label);
+
+ /// Searches for all objects of the given type using the id (`CKA_ID`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::vector<byte>& id);
+
+ /// Searches for all objects of the given type using the label (`CKA_LABEL`) and id (`CKA_ID`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::string& label, const std::vector<byte>& id);
+
+ /// Searches for all objects of the given type
+ template<typename T>
+ static std::vector<T> search(Session& session);
+
+ /// @returns the value of the given attribute (using `C_GetAttributeValue`)
+ secure_vector<byte> get_attribute_value(AttributeType attribute) const;
+
+ /// Sets the given value for the attribute (using `C_SetAttributeValue`)
+ void set_attribute_value(AttributeType attribute, const secure_vector<byte>& value) const;
+
+ /// Destroys the object
+ void destroy() const;
+
+ /**
+ * Copies the object
+ * @param modified_attributes the attributes of the copied object
+ */
+ ObjectHandle copy(const AttributeContainer& modified_attributes) const;
+
+ /// @return the handle of this object.
+ inline ObjectHandle handle() const
+ {
+ return m_handle;
+ }
+
+ /// @return the session this objects belongs to
+ inline Session& session() const
+ {
+ return m_session;
+ }
+
+ /// @return the module this object belongs to
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+ protected:
+ Object(Session& session)
+ : m_session(session)
+ {}
+
+ const std::reference_wrapper<Session> m_session;
+ ObjectHandle m_handle;
+ };
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::vector<Attribute>& search_template)
+ {
+ ObjectFinder finder(session, search_template);
+ std::vector<ObjectHandle> handles = finder.find();
+ std::vector<T> result;
+ result.reserve(handles.size());
+ for(const auto& handle : handles)
+ {
+ result.emplace_back(T(session, handle));
+ }
+ return result;
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::string& label)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_string(AttributeType::Label, label);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::vector<byte>& id)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_binary(AttributeType::Id, id);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::string& label, const std::vector<byte>& id)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_string(AttributeType::Label, label);
+ search_template.add_binary(AttributeType::Id, id);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session)
+ {
+ return search<T>(session, AttributeContainer(T::Class).attributes());
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_randomgenerator.cpp b/src/lib/prov/pkcs11/p11_randomgenerator.cpp
new file mode 100644
index 000000000..eaf9933c6
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_randomgenerator.cpp
@@ -0,0 +1,31 @@
+/*
+* PKCS#11 Random Generator
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_randomgenerator.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+PKCS11_RNG::PKCS11_RNG(Session& session)
+ : m_session(session)
+ {}
+
+void PKCS11_RNG::randomize(Botan::byte output[], std::size_t length)
+ {
+ module()->C_GenerateRandom(m_session.get().handle(), output, length);
+ }
+
+void PKCS11_RNG::add_entropy(const Botan::byte in[], std::size_t length)
+ {
+ module()->C_SeedRandom(m_session.get().handle(), const_cast<Botan::byte*>(in), length);
+ }
+
+}
+}
+
diff --git a/src/lib/prov/pkcs11/p11_randomgenerator.h b/src/lib/prov/pkcs11/p11_randomgenerator.h
new file mode 100644
index 000000000..84673278d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_randomgenerator.h
@@ -0,0 +1,70 @@
+/*
+* PKCS#11 Random Generator
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_RNG_H__
+#define BOTAN_P11_RNG_H__
+
+#include <botan/rng.h>
+#include <botan/p11_session.h>
+#include <botan/entropy_src.h>
+
+#include <string>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Module;
+
+/// A random generator that only fetches random from the PKCS#11 RNG
+class BOTAN_DLL PKCS11_RNG final : public RandomNumberGenerator
+ {
+ public:
+ /// Initialize the RNG with the PKCS#11 session that provides access to the cryptoki functions
+ explicit PKCS11_RNG(Session& session);
+
+ void clear() override
+ {}
+
+ std::string name() const override
+ {
+ return "PKCS11_RNG";
+ }
+
+ /// Always returns true
+ bool is_seeded() const override
+ {
+ return true;
+ }
+
+ /// No operation - always returns 0
+ size_t reseed_with_sources(Entropy_Sources&, size_t, std::chrono::milliseconds) override
+ {
+ return 0;
+ }
+
+ /// @return the module used by this RNG
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+
+ /// Calls `C_GenerateRandom` to generate random data
+ void randomize(Botan::byte output[], std::size_t length) override;
+
+ /// Calls `C_SeedRandom` to add entropy to the random generation function of the token/middleware
+ void add_entropy(const Botan::byte in[], std::size_t length) override;
+
+ private:
+ const std::reference_wrapper<Session> m_session;
+ };
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp
new file mode 100644
index 000000000..331e1d0a7
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_rsa.cpp
@@ -0,0 +1,382 @@
+/*
+* PKCS#11 RSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_rsa.h>
+
+#if defined(BOTAN_HAS_RSA)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/pk_ops.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+#include <botan/rng.h>
+#include <botan/blinding.h>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#else
+ #include <botan/auto_rng.h>
+#endif
+
+namespace Botan {
+
+namespace PKCS11 {
+
+RSA_PublicKeyImportProperties::RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent)
+ : PublicKeyProperties(KeyType::Rsa), m_modulus(modulus), m_pub_exponent(pub_exponent)
+ {
+ add_binary(AttributeType::Modulus, BigInt::encode(m_modulus));
+ add_binary(AttributeType::PublicExponent, BigInt::encode(m_pub_exponent));
+ }
+
+RSA_PublicKeyGenerationProperties::RSA_PublicKeyGenerationProperties(Ulong bits)
+ : PublicKeyProperties(KeyType::Rsa)
+ {
+ add_numeric(AttributeType::ModulusBits, bits);
+ }
+
+PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle)
+ : Object(session, handle)
+ {
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props)
+ : RSA_PublicKey(pubkey_props.modulus(), pubkey_props.pub_exponent()), Object(session, pubkey_props)
+ {}
+
+
+RSA_PrivateKeyImportProperties::RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent)
+ : PrivateKeyProperties(KeyType::Rsa), m_modulus(modulus), m_priv_exponent(priv_exponent)
+ {
+ add_binary(AttributeType::Modulus, BigInt::encode(m_modulus));
+ add_binary(AttributeType::PrivateExponent, BigInt::encode(m_priv_exponent));
+ }
+
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle)
+ : Object(session, handle)
+ {
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props)
+ : Object(session, priv_key_props)
+ {
+ m_n = priv_key_props.modulus();
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, uint32_t bits,
+ const RSA_PrivateKeyGenerationProperties& priv_key_props)
+ : RSA_PublicKey(), Object(session)
+ {
+ RSA_PublicKeyGenerationProperties pub_key_props(bits);
+ pub_key_props.set_encrypt(true);
+ pub_key_props.set_verify(true);
+ pub_key_props.set_token(false); // don't create a persistent public key object
+
+ ObjectHandle pub_key_handle = 0;
+ m_handle = 0;
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 };
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_key_props.data(), pub_key_props.count(), priv_key_props.data(), priv_key_props.count(),
+ &pub_key_handle, &m_handle);
+
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const
+ {
+ auto p = get_attribute_value(AttributeType::Prime1);
+ auto q = get_attribute_value(AttributeType::Prime2);
+ auto e = get_attribute_value(AttributeType::PublicExponent);
+ auto d = get_attribute_value(AttributeType::PrivateExponent);
+ auto n = get_attribute_value(AttributeType::Modulus);
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ System_RNG rng;
+#else
+ AutoSeeded_RNG rng;
+#endif
+
+ return RSA_PrivateKey(rng
+ , BigInt::decode(p)
+ , BigInt::decode(q)
+ , BigInt::decode(e)
+ , BigInt::decode(d)
+ , BigInt::decode(n));
+ }
+
+secure_vector<byte> PKCS11_RSA_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+
+namespace {
+// note: multiple-part decryption operations (with C_DecryptUpdate/C_DecryptFinal)
+// are not supported (PK_Ops::Decryption does not provide an `update` method)
+class PKCS11_RSA_Decryption_Operation : public PK_Ops::Decryption
+ {
+ public:
+ typedef PKCS11_RSA_PrivateKey Key_Type;
+
+ PKCS11_RSA_Decryption_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)),
+ m_powermod(m_key.get_e(), m_key.get_n()), m_blinder(m_key.get_n(),
+ [ this ](const BigInt& k) { return m_powermod(k); },
+ [ this ](const BigInt& k) { return inverse_mod(k, m_key.get_n()); })
+ {
+ m_bits = m_key.get_n().bits() - 1;
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_bits;
+ }
+
+ secure_vector<byte> decrypt(byte& valid_mask, const byte ciphertext[], size_t ciphertext_len) override
+ {
+ valid_mask = 0;
+ m_key.module()->C_DecryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+
+ std::vector<byte> encrypted_data(ciphertext, ciphertext + ciphertext_len);
+
+ // blind for RSA/RAW decryption
+ if(! m_mechanism.padding_size())
+ {
+ encrypted_data = BigInt::encode(m_blinder.blind(BigInt::decode(encrypted_data)));
+ }
+
+ secure_vector<byte> decrypted_data;
+ m_key.module()->C_Decrypt(m_key.session().handle(), encrypted_data, decrypted_data);
+
+ // Unblind for RSA/RAW decryption
+ if(!m_mechanism.padding_size())
+ {
+ secure_vector<byte> unblinded_data = BigInt::encode_locked(m_blinder.unblind(BigInt::decode(decrypted_data)));
+
+ // pad possible leading zeros that were stripped off during conversion to BigInt
+ secure_vector<byte> padded_result(m_key.get_n().bits() / 8 - unblinded_data.size());
+ padded_result.insert(padded_result.end(), unblinded_data.begin(), unblinded_data.end());
+ decrypted_data = padded_result;
+ }
+
+ valid_mask = 0xFF;
+ return decrypted_data;
+ }
+
+ private:
+ const PKCS11_RSA_PrivateKey& m_key;
+ MechanismWrapper m_mechanism;
+ size_t m_bits = 0;
+ Fixed_Exponent_Power_Mod m_powermod;
+ Blinder m_blinder;
+ };
+
+// note: multiple-part encryption operations (with C_EncryptUpdate/C_EncryptFinal)
+// are not supported (PK_Ops::Encryption does not provide an `update` method)
+class PKCS11_RSA_Encryption_Operation : public PK_Ops::Encryption
+ {
+ public:
+ typedef PKCS11_RSA_PublicKey Key_Type;
+
+ PKCS11_RSA_Encryption_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding))
+ {
+ m_bits = 8 * (key.get_n().bytes() - m_mechanism.padding_size()) - 1;
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_bits;
+ }
+
+ secure_vector<byte> encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator&) override
+ {
+ m_key.module()->C_EncryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+
+ secure_vector<byte> encrytped_data;
+ m_key.module()->C_Encrypt(m_key.session().handle(), secure_vector<byte>(msg, msg + msg_len), encrytped_data);
+ return encrytped_data;
+ }
+
+ private:
+ const PKCS11_RSA_PublicKey& m_key;
+ MechanismWrapper m_mechanism;
+ size_t m_bits = 0;
+ };
+
+
+class PKCS11_RSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ typedef PKCS11_RSA_PrivateKey Key_Type;
+
+ PKCS11_RSA_Signature_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding))
+ {}
+
+ size_t message_part_size() const override
+ {
+ return m_key.get_n().bytes();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast< Byte* >(msg), msg_len);
+ }
+
+ secure_vector<byte> sign(RandomNumberGenerator&) override
+ {
+ secure_vector<byte> signature;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_SignFinal(m_key.session().handle(), signature);
+ }
+ m_initialized = false;
+ return signature;
+ }
+
+ private:
+ const PKCS11_RSA_PrivateKey& m_key;
+ bool m_initialized = false;
+ secure_vector<byte> m_first_message;
+ MechanismWrapper m_mechanism;
+ };
+
+
+class PKCS11_RSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ typedef PKCS11_RSA_PublicKey Key_Type;
+
+ PKCS11_RSA_Verification_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding))
+ {}
+
+ size_t message_part_size() const override
+ {
+ return m_key.get_n().bytes();
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_key.get_n().bits() - 1;
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast< Byte* >(msg), msg_len);
+ }
+
+ bool is_valid_signature(const byte sig[], size_t sig_len) override
+ {
+ ReturnValue return_value = ReturnValue::SignatureInvalid;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), m_first_message.size(),
+ const_cast< Byte* >(sig), sig_len, &return_value);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast< Byte* >(sig), sig_len, &return_value);
+ }
+ m_initialized = false;
+ if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid)
+ {
+ throw PKCS11_ReturnError(return_value);
+ }
+ return return_value == ReturnValue::OK;
+ }
+
+ private:
+ const PKCS11_RSA_PublicKey& m_key;
+ bool m_initialized = false;
+ secure_vector<byte> m_first_message;
+ MechanismWrapper m_mechanism;
+ };
+
+BOTAN_REGISTER_TYPE(PK_Ops::Decryption, PKCS11_RSA_Decryption_Operation, "RSA",
+ (make_pk_op<PK_Ops::Decryption, PKCS11_RSA_Decryption_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Encryption, PKCS11_RSA_Encryption_Operation, "RSA",
+ (make_pk_op<PK_Ops::Encryption, PKCS11_RSA_Encryption_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Signature, PKCS11_RSA_Signature_Operation, "RSA",
+ (make_pk_op<PK_Ops::Signature, PKCS11_RSA_Signature_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Verification, PKCS11_RSA_Verification_Operation, "RSA",
+ (make_pk_op<PK_Ops::Verification, PKCS11_RSA_Verification_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+}
+
+PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props,
+ const RSA_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_RSA_PublicKey(session, pub_key_handle), PKCS11_RSA_PrivateKey(session, priv_key_handle));
+ }
+
+}
+}
+#endif
diff --git a/src/lib/prov/pkcs11/p11_rsa.h b/src/lib/prov/pkcs11/p11_rsa.h
new file mode 100644
index 000000000..bf1422dc2
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_rsa.h
@@ -0,0 +1,213 @@
+/*
+* PKCS#11 RSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_RSA_H__
+#define BOTAN_P11_RSA_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_RSA)
+
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+#include <botan/p11_object.h>
+#include <botan/rsa.h>
+
+#include <utility>
+
+namespace Botan {
+namespace PKCS11 {
+
+/// Properties for generating a PKCS#11 RSA public key
+class BOTAN_DLL RSA_PublicKeyGenerationProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param bits length in bits of modulus n
+ explicit RSA_PublicKeyGenerationProperties(Ulong bits);
+
+ /// @param pub_exponent public exponent e
+ inline void set_pub_exponent(const BigInt& pub_exponent = BigInt(0x10001))
+ {
+ add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent));
+ }
+
+ virtual ~RSA_PublicKeyGenerationProperties() = default;
+ };
+
+/// Properties for importing a PKCS#11 RSA public key
+class BOTAN_DLL RSA_PublicKeyImportProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param modulus modulus n
+ /// @param pub_exponent public exponent e
+ RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent);
+
+ /// @return the modulus
+ inline const BigInt& modulus() const
+ {
+ return m_modulus;
+ }
+
+ /// @return the public exponent
+ inline const BigInt& pub_exponent() const
+ {
+ return m_pub_exponent;
+ }
+
+ virtual ~RSA_PublicKeyImportProperties() = default;
+ private:
+ const BigInt m_modulus;
+ const BigInt m_pub_exponent;
+ };
+
+/// Represents a PKCS#11 RSA public key
+class BOTAN_DLL PKCS11_RSA_PublicKey final : public RSA_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PublicKey;
+
+ /**
+ * Creates a PKCS11_RSA_PublicKey object from an existing PKCS#11 RSA public key
+ * @param session the session to use
+ * @param handle the handle of the RSA public key
+ */
+ PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a RSA public key
+ * @param session the session to use
+ * @param pubkey_props the attributes of the public key
+ */
+ PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props);
+ };
+
+/// Properties for importing a PKCS#11 RSA private key
+class BOTAN_DLL RSA_PrivateKeyImportProperties final : public PrivateKeyProperties
+ {
+ public:
+ /**
+ * @param modulus modulus n
+ * @param priv_exponent private exponent d
+ */
+ RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent);
+
+ /// @param pub_exponent public exponent e
+ inline void set_pub_exponent(const BigInt& pub_exponent)
+ {
+ add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent));
+ }
+
+ /// @param prime1 prime p
+ inline void set_prime_1(const BigInt& prime1)
+ {
+ add_binary(AttributeType::Prime1, BigInt::encode(prime1));
+ }
+
+ /// @param prime2 prime q
+ inline void set_prime_2(const BigInt& prime2)
+ {
+ add_binary(AttributeType::Prime2, BigInt::encode(prime2));
+ }
+
+ /// @param exp1 private exponent d modulo p-1
+ inline void set_exponent_1(const BigInt& exp1)
+ {
+ add_binary(AttributeType::Exponent1, BigInt::encode(exp1));
+ }
+
+ /// @param exp2 private exponent d modulo q-1
+ inline void set_exponent_2(const BigInt& exp2)
+ {
+ add_binary(AttributeType::Exponent2, BigInt::encode(exp2));
+ }
+
+ /// @param coeff CRT coefficient q^-1 mod p
+ inline void set_coefficient(const BigInt& coeff)
+ {
+ add_binary(AttributeType::Coefficient, BigInt::encode(coeff));
+ }
+
+ /// @return the modulus
+ inline const BigInt& modulus() const
+ {
+ return m_modulus;
+ }
+
+ /// @return the private exponent
+ inline const BigInt& priv_exponent() const
+ {
+ return m_priv_exponent;
+ }
+
+ virtual ~RSA_PrivateKeyImportProperties() = default;
+
+ private:
+ const BigInt m_modulus;
+ const BigInt m_priv_exponent;
+ };
+
+/// Properties for generating a PKCS#11 RSA private key
+class BOTAN_DLL RSA_PrivateKeyGenerationProperties final : public PrivateKeyProperties
+ {
+ public:
+ RSA_PrivateKeyGenerationProperties()
+ : PrivateKeyProperties(KeyType::Rsa)
+ {}
+
+ virtual ~RSA_PrivateKeyGenerationProperties() = default;
+ };
+
+/// Represents a PKCS#11 RSA private key
+class BOTAN_DLL PKCS11_RSA_PrivateKey final : public Private_Key,
+ public RSA_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PrivateKey;
+
+ /// Creates a PKCS11_RSA_PrivateKey object from an existing PKCS#11 RSA private key
+ PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a RSA private key
+ * @param session the session to use
+ * @param priv_key_props the properties of the RSA private key
+ */
+ PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props);
+
+ /**
+ * Generates a PKCS#11 RSA private key
+ * @param session
+ * @param bits length in bits of modulus n
+ * @param priv_key_props the properties of the RSA private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props);
+
+ /// @return the exported RSA private key
+ RSA_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+ };
+
+using PKCS11_RSA_KeyPair = std::pair<PKCS11_RSA_PublicKey, PKCS11_RSA_PrivateKey>;
+
+/**
+* RSA key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props properties of the public key
+* @param priv_props properties of the private key
+*/
+BOTAN_DLL PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props,
+ const RSA_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+#endif
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_session.cpp b/src/lib/prov/pkcs11/p11_session.cpp
new file mode 100644
index 000000000..ceb316169
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_session.cpp
@@ -0,0 +1,89 @@
+/*
+* PKCS#11 Session
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_session.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+Session::Session(Slot& slot, bool read_only)
+ : Session(slot, PKCS11::flags(Flag::SerialSession | (read_only ? Flag::None : Flag::RwSession)), nullptr, nullptr)
+ {}
+
+Session::Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback)
+ : m_slot(slot), m_handle(0), m_logged_in(false)
+ {
+ module()->C_OpenSession(m_slot.slot_id(), flags, callback_data, notify_callback, &m_handle);
+ }
+
+Session::Session(Slot& slot, SessionHandle handle)
+ : m_slot(slot), m_handle(handle)
+ {
+ SessionInfo info = get_info();
+ if(info.state == static_cast<CK_STATE>(SessionState::RoPublicSession)
+ || info.state == static_cast<CK_STATE>(SessionState::RwPublicSession))
+ {
+ m_logged_in = false;
+ }
+ else
+ {
+ m_logged_in = true;
+ }
+ }
+
+Session::~Session() BOTAN_NOEXCEPT
+ {
+ if(m_handle)
+ {
+ if(m_logged_in)
+ {
+ module()->C_Logout(m_handle, nullptr);
+ }
+ module()->C_CloseSession(m_handle, nullptr);
+ m_handle = 0;
+ }
+ }
+
+SessionHandle Session::release()
+ {
+ SessionHandle handle = 0;
+ std::swap(handle, m_handle);
+ return handle;
+ }
+
+void Session::login(UserType user_type, const secure_string& pin)
+ {
+ module()->C_Login(m_handle, user_type, pin);
+ m_logged_in = true;
+ }
+
+void Session::logoff()
+ {
+ module()->C_Logout(m_handle);
+ m_logged_in = false;
+ }
+
+SessionInfo Session::get_info() const
+ {
+ SessionInfo info;
+ module()->C_GetSessionInfo(m_handle, &info);
+ return info;
+ }
+
+void Session::set_pin(const secure_string& old_pin, const secure_string& new_pin) const
+ {
+ module()->C_SetPIN(m_handle, old_pin, new_pin);
+ }
+
+void Session::init_pin(const secure_string& new_pin)
+ {
+ module()->C_InitPIN(m_handle, new_pin);
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_session.h b/src/lib/prov/pkcs11/p11_session.h
new file mode 100644
index 000000000..49f223a90
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_session.h
@@ -0,0 +1,105 @@
+/*
+* PKCS#11 Session
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_SESSION_H__
+#define BOTAN_P11_SESSION_H__
+
+#include <botan/p11.h>
+#include <botan/p11_slot.h>
+
+#include <utility>
+
+namespace Botan {
+namespace PKCS11 {
+class Module;
+
+/// Represents a PKCS#11 session
+class BOTAN_DLL Session final
+ {
+ public:
+ /**
+ * @param slot the slot to use
+ * @param read_only true if the session should be read only, false to create a read-write session
+ */
+ Session(Slot& slot, bool read_only);
+
+ /**
+ * @param slot the slot to use
+ * @param flags the flags to use for the session. Remark: Flag::SerialSession is mandatory
+ * @param callback_data application-defined pointer to be passed to the notification callback
+ * @param notify_callback address of the notification callback function
+ */
+ Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback);
+
+ /// Takes ownership of a session
+ Session(Slot& slot, SessionHandle handle);
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ Session(Session&& other) = default;
+ Session& operator=(Session&& other) = default;
+#endif
+
+ // Dtor calls C_CloseSession() and eventually C_Logout. A copy could close the session while the origin still exists
+ Session(const Session& other) = delete;
+ Session& operator=(const Session& other) = delete;
+
+ /// Logout user and close the session on destruction
+ ~Session() BOTAN_NOEXCEPT;
+
+ /// @return a reference to the slot
+ inline const Slot& slot() const
+ {
+ return m_slot;
+ }
+
+ /// @return the session handle of this session
+ inline SessionHandle handle() const
+ {
+ return m_handle;
+ }
+
+ /// @return a reference to the used module
+ inline Module& module() const
+ {
+ return m_slot.module();
+ }
+
+ /// @return the released session handle
+ SessionHandle release();
+
+ /**
+ * Login to this session
+ * @param userType the user type to use for the login
+ * @param pin the PIN of the user
+ */
+ void login(UserType userType, const secure_string& pin);
+
+ /// Logout from this session
+ void logoff();
+
+ /// @return information about this session
+ SessionInfo get_info() const;
+
+ /// Calls `C_SetPIN` to change the PIN using the old PIN (requires a logged in session)
+ void set_pin(const secure_string& old_pin, const secure_string& new_pin) const;
+
+ /// Calls `C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session)
+ void init_pin(const secure_string& new_pin);
+
+ private:
+ const Slot& m_slot;
+ SessionHandle m_handle;
+ bool m_logged_in;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_slot.cpp b/src/lib/prov/pkcs11/p11_slot.cpp
new file mode 100644
index 000000000..95a0fad50
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_slot.cpp
@@ -0,0 +1,60 @@
+/*
+* PKCS#11 Slot
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_slot.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+Slot::Slot(Module& module, SlotId slot_id)
+ : m_module(module), m_slot_id(slot_id)
+ {}
+
+SlotInfo Slot::get_slot_info() const
+ {
+ SlotInfo slot_info = {};
+ m_module.get()->C_GetSlotInfo(m_slot_id, &slot_info);
+ return slot_info;
+ }
+
+std::vector<MechanismType> Slot::get_mechanism_list() const
+ {
+ std::vector<MechanismType> mechanism_list;
+ m_module.get()->C_GetMechanismList(m_slot_id, mechanism_list);
+ return mechanism_list;
+ }
+
+MechanismInfo Slot::get_mechanism_info(MechanismType mechanism_type) const
+ {
+ MechanismInfo mechanism_info = {};
+ m_module.get()->C_GetMechanismInfo(m_slot_id, mechanism_type, &mechanism_info);
+ return mechanism_info;
+ }
+
+std::vector<SlotId> Slot::get_available_slots(Module& module, bool token_present)
+ {
+ std::vector<SlotId> slot_vec;
+ module->C_GetSlotList(token_present, slot_vec);
+ return slot_vec;
+ }
+
+TokenInfo Slot::get_token_info() const
+ {
+ TokenInfo token_info;
+ m_module.get()->C_GetTokenInfo(m_slot_id, &token_info);
+ return token_info;
+ }
+
+void Slot::initialize(const std::string& label, const secure_string& so_pin) const
+ {
+ m_module.get()->C_InitToken(m_slot_id, so_pin, label);
+ }
+}
+
+}
diff --git a/src/lib/prov/pkcs11/p11_slot.h b/src/lib/prov/pkcs11/p11_slot.h
new file mode 100644
index 000000000..92e585ba1
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_slot.h
@@ -0,0 +1,79 @@
+/*
+* PKCS#11 Slot
+* (C) 2016 Daniel Neus
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_SLOT_H__
+#define BOTAN_P11_SLOT_H__
+
+#include <string>
+#include <vector>
+#include <functional>
+
+#include <botan/p11.h>
+#include <botan/p11_module.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+/// Represents a PKCS#11 Slot, i.e., a card reader
+class BOTAN_DLL Slot final
+ {
+ public:
+ /**
+ * @param module the PKCS#11 module to use
+ * @param slot_id the slot id to use
+ */
+ Slot(Module& module, SlotId slot_id);
+
+ /// @return a reference to the module that is used
+ inline Module& module() const
+ {
+ return m_module;
+ }
+
+ /// @return the slot id
+ inline SlotId slot_id() const
+ {
+ return m_slot_id;
+ }
+
+ /**
+ * Get available slots
+ * @param module the module to use
+ * @param token_present true if only slots with attached tokens should be returned, false for all slots
+ * @return a list of available slots (calls C_GetSlotList)
+ */
+ static std::vector<SlotId> get_available_slots(Module& module, bool token_present);
+
+ /// @return information about the slot (`C_GetSlotInfo`)
+ SlotInfo get_slot_info() const;
+
+ /// Obtains a list of mechanism types supported by the slot (`C_GetMechanismList`)
+ std::vector<MechanismType> get_mechanism_list() const;
+
+ /// Obtains information about a particular mechanism possibly supported by a slot (`C_GetMechanismInfo`)
+ MechanismInfo get_mechanism_info(MechanismType mechanism_type) const;
+
+ /// Obtains information about a particular token in the system (`C_GetTokenInfo`)
+ TokenInfo get_token_info() const;
+
+ /**
+ * Calls `C_InitToken` to initialize the token
+ * @param label the label for the token (must not exceed 32 bytes according to PKCS#11)
+ * @param so_pin the PIN of the security officer
+ */
+ void initialize(const std::string& label, const secure_string& so_pin) const;
+
+ private:
+ const std::reference_wrapper<Module> m_module;
+ const SlotId m_slot_id;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_x509.cpp b/src/lib/prov/pkcs11/p11_x509.cpp
new file mode 100644
index 000000000..76b120368
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_x509.cpp
@@ -0,0 +1,37 @@
+/*
+* PKCS#11 X.509
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_x509.h>
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+
+namespace Botan {
+namespace PKCS11 {
+
+X509_CertificateProperties::X509_CertificateProperties(const std::vector<byte>& subject, const std::vector<byte>& value)
+ : CertificateProperties(CertificateType::X509), m_subject(subject), m_value(value)
+ {
+ add_binary(AttributeType::Subject, m_subject);
+ add_binary(AttributeType::Value, m_value);
+ }
+
+PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, ObjectHandle handle)
+ : Object(session, handle), X509_Certificate(unlock(get_attribute_value(AttributeType::Value)))
+ {
+ }
+
+PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props)
+ : Object(session, props), X509_Certificate(props.value())
+ {
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_x509.h b/src/lib/prov/pkcs11/p11_x509.h
new file mode 100644
index 000000000..f0e025ff4
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_x509.h
@@ -0,0 +1,115 @@
+/*
+* PKCS#11 X.509
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_X509_H__
+#define BOTAN_P11_X509_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+
+#include <botan/p11_object.h>
+
+#include <botan/x509cert.h>
+
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Session;
+
+/// Common attributes of all PKCS#11 X509 certificates
+class BOTAN_DLL X509_CertificateProperties final : public CertificateProperties
+ {
+ public:
+ /**
+ * @param subject DER-encoding of the certificate subject name
+ * @param value BER-encoding of the certificate
+ */
+ X509_CertificateProperties(const std::vector<byte>& subject, const std::vector<byte>& value);
+
+ /// @param id key identifier for public/private key pair
+ inline void set_id(const std::vector<byte>& id)
+ {
+ add_binary(AttributeType::Id, id);
+ }
+
+ /// @param issuer DER-encoding of the certificate issuer name
+ inline void set_issuer(const std::vector<byte>& issuer)
+ {
+ add_binary(AttributeType::Issuer, issuer);
+ }
+
+ /// @param serial DER-encoding of the certificate serial number
+ inline void set_serial(const std::vector<byte>& serial)
+ {
+ add_binary(AttributeType::SerialNumber, serial);
+ }
+
+ /// @param hash hash value of the subject public key
+ inline void set_subject_pubkey_hash(const std::vector<byte>& hash)
+ {
+ add_binary(AttributeType::HashOfSubjectPublicKey, hash);
+ }
+
+ /// @param hash hash value of the issuer public key
+ inline void set_issuer_pubkey_hash(const std::vector<byte>& hash)
+ {
+ add_binary(AttributeType::HashOfIssuerPublicKey, hash);
+ }
+
+ /// @param alg defines the mechanism used to calculate `CKA_HASH_OF_SUBJECT_PUBLIC_KEY` and `CKA_HASH_OF_ISSUER_PUBLIC_KEY`
+ inline void set_hash_alg(MechanismType alg)
+ {
+ add_numeric(AttributeType::NameHashAlgorithm, static_cast<Ulong>(alg));
+ }
+
+ /// @return the subject
+ inline const std::vector<byte>& subject() const
+ {
+ return m_subject;
+ }
+
+ /// @return the BER-encoding of the certificate
+ inline const std::vector<byte>& value() const
+ {
+ return m_value;
+ }
+
+ private:
+ const std::vector<byte> m_subject;
+ const std::vector<byte> m_value;
+ };
+
+/// Represents a PKCS#11 X509 certificate
+class BOTAN_DLL PKCS11_X509_Certificate final : public Object, public X509_Certificate
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::Certificate;
+
+ /**
+ * Create a PKCS11_X509_Certificate object from an existing PKCS#11 X509 cert
+ * @param session the session to use
+ * @param handle the handle of the X.509 certificate
+ */
+ PKCS11_X509_Certificate(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a X.509 certificate
+ * @param session the session to use
+ * @param props the attributes of the X.509 certificate
+ */
+ PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props);
+ };
+
+}
+}
+
+#endif
+
+#endif
diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp
index c0795942b..ce6b61a1d 100644
--- a/src/lib/utils/dyn_load/dyn_load.cpp
+++ b/src/lib/utils/dyn_load/dyn_load.cpp
@@ -5,7 +5,7 @@
* Botan is released under the Simplified BSD License (see license.txt)
*/
-#include <botan/internal/dyn_load.h>
+#include <botan/dyn_load.h>
#include <botan/build.h>
#include <botan/exceptn.h>
diff --git a/src/lib/utils/dyn_load/dyn_load.h b/src/lib/utils/dyn_load/dyn_load.h
index 7a9f4a83c..3a155f3de 100644
--- a/src/lib/utils/dyn_load/dyn_load.h
+++ b/src/lib/utils/dyn_load/dyn_load.h
@@ -9,13 +9,14 @@
#define BOTAN_DYNAMIC_LOADER_H__
#include <string>
+#include <botan/build.h>
namespace Botan {
/**
* Represents a DLL or shared object
*/
-class Dynamically_Loaded_Library
+class BOTAN_DLL Dynamically_Loaded_Library
{
public:
/**
diff --git a/src/lib/utils/dyn_load/info.txt b/src/lib/utils/dyn_load/info.txt
index 0cc4e4e73..22a79be43 100644
--- a/src/lib/utils/dyn_load/info.txt
+++ b/src/lib/utils/dyn_load/info.txt
@@ -1,4 +1,4 @@
-define DYNAMIC_LOADER 20131128
+define DYNAMIC_LOADER 20160310
load_on dep
@@ -11,18 +11,12 @@ openbsd
qnx
solaris
windows
+darwin
</os>
<libs>
android -> dl
linux -> dl
solaris -> dl
+darwin -> dl
</libs>
-
-<source>
-dyn_load.cpp
-</source>
-
-<header:internal>
-dyn_load.h
-</header:internal>
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
index c15fab438..a330bd79a 100644
--- a/src/tests/main.cpp
+++ b/src/tests/main.cpp
@@ -31,7 +31,7 @@ namespace {
class Test_Runner : public Botan_CLI::Command
{
public:
- Test_Runner() : Command("test --threads=0 --soak=5 --drbg-seed= --data-dir= --log-success *suites") {}
+ Test_Runner() : Command("test --threads=0 --soak=5 --drbg-seed= --data-dir= --pkcs11-lib= --log-success *suites") {}
std::string help_text() const override
{
@@ -73,6 +73,7 @@ class Test_Runner : public Botan_CLI::Command
const std::string drbg_seed = get_arg("drbg-seed");
const bool log_success = flag_set("log-success");
const std::string data_dir = get_arg_or("data-dir", "src/tests/data");
+ const std::string pkcs11_lib = get_arg("pkcs11-lib");
std::vector<std::string> req = get_arg_list("suites");
@@ -88,6 +89,19 @@ class Test_Runner : public Botan_CLI::Command
std::set<std::string> all_others = Botan_Tests::Test::registered_tests();
+ // do not run pkcs11 tests by default
+ for(std::set<std::string>::iterator iter = all_others.begin(); iter != all_others.end();)
+ {
+ if((*iter).find("pkcs11") != std::string::npos)
+ {
+ iter = all_others.erase(iter);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
for(auto f : req)
{
all_others.erase(f);
@@ -95,6 +109,11 @@ class Test_Runner : public Botan_CLI::Command
req.insert(req.end(), all_others.begin(), all_others.end());
}
+ else if(req.size() == 1 && req.at(0) == "pkcs11")
+ {
+ req = {"pkcs11-manage", "pkcs11-module", "pkcs11-slot", "pkcs11-session", "pkcs11-object", "pkcs11-rsa",
+ "pkcs11-ecdsa", "pkcs11-ecdh", "pkcs11-rng", "pkcs11-x509"};
+ }
output() << "Testing " << Botan::version_string() << "\n";
output() << "Starting tests";
@@ -104,6 +123,11 @@ class Test_Runner : public Botan_CLI::Command
output() << " soak level:" << soak_level;
+ if(! pkcs11_lib.empty())
+ {
+ output() << " pkcs11 library:" << pkcs11_lib;
+ }
+
std::unique_ptr<Botan::RandomNumberGenerator> rng;
#if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
@@ -137,7 +161,7 @@ class Test_Runner : public Botan_CLI::Command
output() << "\n";
- Botan_Tests::Test::setup_tests(soak_level, log_success, data_dir, rng.get());
+ Botan_Tests::Test::setup_tests(soak_level, log_success, data_dir, pkcs11_lib, rng.get());
const size_t failed = run_tests(req, output(), threads);
diff --git a/src/tests/test_pkcs11.cpp b/src/tests/test_pkcs11.cpp
new file mode 100644
index 000000000..676e3f21a
--- /dev/null
+++ b/src/tests/test_pkcs11.cpp
@@ -0,0 +1,42 @@
+/*
+* (C) 2016 Daniel Neus
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "test_pkcs11.h"
+
+namespace Botan_Tests {
+using namespace Botan;
+using namespace PKCS11;
+
+std::vector<Test::Result> PKCS11_Test::run_pkcs11_tests(const std::string& name,
+ std::vector<std::function<Test::Result()>>& fns)
+ {
+ std::vector<Test::Result> results;
+
+ for(size_t i = 0; i != fns.size(); ++i)
+ {
+ try
+ {
+ results.push_back(fns[ i ]());
+ }
+ catch(PKCS11_ReturnError& e)
+ {
+ results.push_back(Test::Result::Failure(name + " test " + std::to_string(i), e.what()));
+
+ if(e.get_return_value() == ReturnValue::PinIncorrect)
+ {
+ break; // Do not continue to not potentially lock the token
+ }
+ }
+ catch(std::exception& e)
+ {
+ results.push_back(Test::Result::Failure(name + " test " + std::to_string(i), e.what()));
+ }
+ }
+
+ return results;
+ }
+
+}
diff --git a/src/tests/test_pkcs11.h b/src/tests/test_pkcs11.h
new file mode 100644
index 000000000..8606612d3
--- /dev/null
+++ b/src/tests/test_pkcs11.h
@@ -0,0 +1,50 @@
+/*
+* (C) 2016 Daniel Neus
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_TESTS_PKCS11_H__
+#define BOTAN_TESTS_PKCS11_H__
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_PKCS11)
+ #include <botan/p11.h>
+#endif
+
+#include <botan/secmem.h>
+
+#include <string>
+#include <vector>
+#include <functional>
+
+namespace Botan_Tests {
+
+#if defined(BOTAN_HAS_PKCS11)
+
+// PIN is expected to be set to "123456" prior to running the tests
+const std::string PIN = "123456";
+const auto PIN_SECVEC = Botan::PKCS11::secure_string(PIN.begin(), PIN.end());
+
+const std::string TEST_PIN = "654321";
+const auto TEST_PIN_SECVEC = Botan::PKCS11::secure_string(TEST_PIN.begin(), TEST_PIN.end());
+
+// SO PIN is expected to be set to "12345678" prior to running the tests
+const std::string SO_PIN = "12345678";
+const auto SO_PIN_SECVEC = Botan::PKCS11::secure_string(SO_PIN.begin(), SO_PIN.end());
+
+const std::string TEST_SO_PIN = "87654321";
+const auto TEST_SO_PIN_SECVEC = Botan::PKCS11::secure_string(TEST_SO_PIN.begin(), TEST_SO_PIN.end());
+
+class PKCS11_Test : public Test
+ {
+ protected:
+ static std::vector<Test::Result> run_pkcs11_tests(const std::string& name,
+ std::vector<std::function<Test::Result()>>& fns);
+ };
+
+#endif
+}
+
+#endif
diff --git a/src/tests/test_pkcs11_high_level.cpp b/src/tests/test_pkcs11_high_level.cpp
new file mode 100644
index 000000000..f68203496
--- /dev/null
+++ b/src/tests/test_pkcs11_high_level.cpp
@@ -0,0 +1,1509 @@
+/*
+* (C) 2016 Daniel Neus
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+#include "test_pkcs11.h"
+
+#include <string>
+#include <vector>
+#include <functional>
+#include <memory>
+#include <array>
+#include <type_traits>
+#include <map>
+#include <numeric>
+
+#if defined(BOTAN_HAS_PKCS11)
+ #include <botan/p11.h>
+ #include <botan/p11_slot.h>
+ #include <botan/p11_session.h>
+ #include <botan/p11_module.h>
+ #include <botan/p11_object.h>
+ #include <botan/p11_randomgenerator.h>
+#endif
+
+#include <botan/der_enc.h>
+#include <botan/pubkey.h>
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+ #include <botan/p11_rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ #include <botan/ecc_key.h>
+ #include <botan/ecdsa.h>
+ #include <botan/ecdh.h>
+ #include <botan/p11_ecc_key.h>
+ #include <botan/p11_ecdh.h>
+ #include <botan/p11_ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+ #include <botan/p11_x509.h>
+#endif
+
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+ #include <botan/auto_rng.h>
+#endif
+
+#if defined(BOTAN_HAS_HMAC_DRBG)
+ #include <botan/hmac_drbg.h>
+#endif
+
+namespace Botan_Tests {
+
+namespace {
+
+#if defined(BOTAN_HAS_PKCS11)
+
+using namespace Botan;
+using namespace PKCS11;
+
+class TestSession
+ {
+ public:
+ explicit TestSession(bool login) :
+ m_module(new Module(Test::pkcs11_lib()))
+ {
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(*m_module, true);
+ m_slot.reset(new Slot(*m_module, slot_vec.at(0)));
+ m_session.reset(new Session(*m_slot, false));
+ if(login)
+ {
+ m_session->login(UserType::User, PIN_SECVEC);
+ }
+ }
+
+ inline Module& module() const { return *m_module; }
+ inline Slot& slot() const { return *m_slot; }
+ inline Session& session() const { return *m_session; }
+
+ private:
+ std::unique_ptr<Module> m_module = nullptr;
+ std::unique_ptr<Slot> m_slot = nullptr;
+ std::unique_ptr<Session> m_session = nullptr;
+ };
+
+/***************************** Module *****************************/
+
+Test::Result test_module_ctor()
+ {
+ Test::Result result("Module ctor");
+
+ result.test_throws("Module ctor fails for non existent path", []()
+ {
+ Module module("/a/b/c");
+ });
+
+ Module module(Test::pkcs11_lib());
+ result.test_success("Module ctor did not throw and completed successfully");
+
+ return result;
+ }
+
+Test::Result test_module_reload()
+ {
+ Test::Result result("Module reload");
+
+ Module module(Test::pkcs11_lib());
+
+ module.reload();
+ result.test_success("Module reload did not throw and completed successfully");
+
+ module.get_info();
+ result.test_success("Module get_info() still works after reload");
+
+ return result;
+ }
+
+Test::Result test_multiple_modules()
+ {
+ Test::Result result("Module copy");
+ Module first_module(Test::pkcs11_lib());
+
+ result.test_throws("Module ctor fails if module is already initialized", []()
+ {
+ Module second_module(Test::pkcs11_lib());
+ });
+
+ return result;
+ }
+
+Test::Result test_module_get_info()
+ {
+ Test::Result result("Module info");
+
+ Module module(Test::pkcs11_lib());
+
+ Info info = module.get_info();
+ result.test_ne("Cryptoki version != 0", info.cryptokiVersion.major, 0);
+
+ return result;
+ }
+
+class Module_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_module_ctor,
+ test_multiple_modules,
+ test_module_get_info,
+ test_module_reload
+
+ };
+
+ return run_pkcs11_tests("Module", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-module", Module_Tests);
+
+/***************************** Slot *****************************/
+
+Test::Result test_slot_get_available_slots()
+ {
+ Test::Result result("Slot get_available_slots");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ result.test_gte("Available Slots with attached token >= 1", slot_vec.size(), 1);
+
+ return result;
+ }
+
+Test::Result test_slot_ctor()
+ {
+ Test::Result result("Slot ctor");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+
+ Slot slot(module, slot_vec.at(0));
+ result.test_success("Slot ctor completed successfully");
+ result.test_is_eq(slot.slot_id(), slot_vec.at(0));
+
+ return result;
+ }
+
+Test::Result test_get_slot_info()
+ {
+ Test::Result result("Slot get_slot_info");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ SlotInfo info = slot.get_slot_info();
+ std::string description = reinterpret_cast< char* >(info.slotDescription);
+ result.confirm("Slot description is not empty", !description.empty());
+
+ return result;
+ }
+
+Test::Result test_get_token_info()
+ {
+ Test::Result result("Slot get_token_info");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ TokenInfo info = slot.get_token_info();
+ std::string label = reinterpret_cast< char* >(info.label);
+ result.confirm("Token label is not empty", ! label.empty());
+
+ return result;
+ }
+
+Test::Result test_get_mechanism_list()
+ {
+ Test::Result result("Slot get_mechanism_list");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ std::vector<MechanismType> mechanisms = slot.get_mechanism_list();
+ result.confirm("The Slot supports at least one mechanism", !mechanisms.empty());
+
+ return result;
+ }
+
+Test::Result test_get_mechanisms_info()
+ {
+ Test::Result result("Slot get_mechanism_info");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ slot.get_mechanism_info(MechanismType::RsaPkcsKeyPairGen);
+ result.test_success("get_mechanism_info() completed successfully.");
+
+ return result;
+ }
+
+class Slot_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_slot_get_available_slots,
+ test_slot_ctor,
+ test_get_slot_info,
+ test_get_token_info,
+ test_get_mechanism_list,
+ test_get_mechanisms_info
+ };
+
+ return run_pkcs11_tests("Slot", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-slot", Slot_Tests);
+
+/***************************** Session *****************************/
+
+Test::Result test_session_ctor()
+ {
+ Test::Result result("Session ctor");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ {
+ Session read_only_session(slot, true);
+ result.test_success("read only session opened successfully");
+ }
+ {
+ Session read_write_session(slot, false);
+ result.test_success("read write session opened successfully");
+ }
+ {
+ Flags flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ Session read_write_session2(slot, flags, nullptr, nullptr);
+ result.test_success("read write session with flags param opened successfully");
+ }
+ {
+ Session read_only_session(slot, true);
+ Session read_write_session(slot, false);
+ result.test_success("Opened multiple sessions successfully");
+ }
+
+ return result;
+ }
+
+Test::Result test_session_release()
+ {
+ Test::Result result("Session release/take ownership");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ Session session(slot, false);
+ SessionHandle handle = session.release();
+
+ Session session2(slot, handle);
+ result.test_success("releasing ownership and taking ownership works as expected.");
+
+ return result;
+ }
+
+Test::Result test_session_login_logout()
+ {
+ Test::Result result("Session login/logout");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ Session session(slot, false);
+ session.login(UserType::User, PIN_SECVEC);
+ session.logoff();
+ result.test_success("user login/logout succeeded");
+
+ session.login(UserType::SO, SO_PIN_SECVEC);
+ result.test_success("SO login succeeded");
+
+ return result;
+ }
+
+Test::Result test_session_info()
+ {
+ Test::Result result("Session session info");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ Session session(slot, false);
+ SessionInfo info = session.get_info();
+ result.test_is_eq("slot id is correct", info.slotID, slot_vec.at(0));
+ result.test_is_eq("state is a read write public session", info.state,
+ static_cast<CK_STATE>(SessionState::RwPublicSession));
+
+ session.login(UserType::User, PIN_SECVEC);
+ info = session.get_info();
+ result.test_is_eq("state is a read write user session", info.state,
+ static_cast<CK_STATE>(SessionState::RwUserFunctions));
+
+ session.logoff();
+ result.test_success("user login/logout succeeded");
+
+ session.login(UserType::SO, SO_PIN_SECVEC);
+ result.test_success("SO login succeeded");
+
+ return result;
+ }
+
+class Session_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_session_ctor,
+ test_session_release,
+ test_session_login_logout,
+ test_session_info
+ };
+
+ return run_pkcs11_tests("Session", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-session", Session_Tests);
+
+/***************************** Object *****************************/
+
+Test::Result test_attribute_container()
+ {
+ Test::Result result("AttributeContainer");
+
+ AttributeContainer attributes;
+ attributes.add_class(ObjectClass::PrivateKey);
+
+ std::string label("test");
+ attributes.add_string(AttributeType::Label, label);
+
+ std::vector<byte> bin(4);
+ attributes.add_binary(AttributeType::Value, bin);
+
+ attributes.add_bool(AttributeType::Sensitive, true);
+ attributes.add_numeric(AttributeType::ObjectId, 12);
+
+ result.test_eq("Five elements in attribute container", attributes.count(), 5);
+
+ return result;
+ }
+
+Test::Result test_create_destroy_data_object()
+ {
+ Test::Result result("Object create/delete data object");
+
+ TestSession test_session(true);
+
+ std::string value_string("test data");
+ secure_vector<byte> value(value_string.begin(), value_string.end());
+
+ std::size_t id = 1337;
+ std::string label = "Botan test data object";
+ std::string application = "Botan test application";
+ DataObjectProperties data_obj_props;
+ data_obj_props.set_application(application);
+ data_obj_props.set_label(label);
+ data_obj_props.set_value(value);
+ data_obj_props.set_token(true);
+ data_obj_props.set_modifiable(true);
+ data_obj_props.set_object_id(DER_Encoder().encode(id).get_contents_unlocked());
+
+ Object data_obj(test_session.session(), data_obj_props);
+ result.test_success("Data object creation was successful");
+
+ data_obj.destroy();
+ result.test_success("Data object deletion was successful");
+
+ return result;
+ }
+
+Test::Result test_get_set_attribute_values()
+ {
+ Test::Result result("Object get/set attributes");
+
+ TestSession test_session(true);
+
+ // create object
+ std::string value_string("test data");
+ secure_vector<byte> value(value_string.begin(), value_string.end());
+
+ std::size_t id = 1337;
+ std::string label = "Botan test data object";
+ std::string application = "Botan test application";
+ DataObjectProperties data_obj_props;
+ data_obj_props.set_application(application);
+ data_obj_props.set_label(label);
+ data_obj_props.set_value(value);
+ data_obj_props.set_token(true);
+ data_obj_props.set_modifiable(true);
+ data_obj_props.set_object_id(DER_Encoder().encode(id).get_contents_unlocked());
+ Object data_obj(test_session.session(), data_obj_props);
+
+ // get attribute
+ secure_vector<byte> retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
+ std::string retrieved_label_string(retrieved_label.begin(), retrieved_label.end());
+ result.test_eq("label was set correctly", retrieved_label_string, label);
+
+ // set attribute
+ std::string new_label = "Botan test modified data object label";
+ secure_vector<byte> new_label_secvec(new_label.begin(), new_label.end());
+ data_obj.set_attribute_value(AttributeType::Label, new_label_secvec);
+
+ // get and check attribute
+ retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
+ retrieved_label_string = std::string(retrieved_label.begin(), retrieved_label.end());
+ result.test_eq("label was modified correctly", retrieved_label_string, new_label);
+
+ data_obj.destroy();
+ return result;
+ }
+
+Test::Result test_object_finder()
+ {
+ Test::Result result("ObjectFinder");
+
+ TestSession test_session(true);
+
+ // create object
+ std::string value_string("test data");
+ secure_vector<byte> value(value_string.begin(), value_string.end());
+
+ std::size_t id = 1337;
+ std::string label = "Botan test data object";
+ std::string application = "Botan test application";
+ DataObjectProperties data_obj_props;
+ data_obj_props.set_application(application);
+ data_obj_props.set_label(label);
+ data_obj_props.set_value(value);
+ data_obj_props.set_token(true);
+ data_obj_props.set_modifiable(true);
+ data_obj_props.set_object_id(DER_Encoder().encode(id).get_contents_unlocked());
+ Object data_obj(test_session.session(), data_obj_props);
+
+ // search created object
+ AttributeContainer search_template;
+ search_template.add_string(AttributeType::Label, label);
+ ObjectFinder finder(test_session.session(), search_template.attributes());
+
+ auto search_result = finder.find();
+ result.test_eq("one object found", search_result.size(), 1);
+ finder.finish();
+
+ Object obj_found(test_session.session(), search_result.at(0));
+ result.test_eq("found the object just created (same application)",
+ obj_found.get_attribute_value(AttributeType::Application) , data_obj.get_attribute_value(AttributeType::Application));
+
+ auto search_result2 = Object::search<Object>(test_session.session(), search_template.attributes());
+ result.test_eq("found the object just created (same label)", obj_found.get_attribute_value(AttributeType::Label),
+ search_result2.at(0).get_attribute_value(AttributeType::Label));
+
+ data_obj.destroy();
+ return result;
+ }
+
+Test::Result test_object_copy()
+ {
+ Test::Result result("Object copy");
+
+ TestSession test_session(true);
+
+ // create object
+ std::string value_string("test data");
+ secure_vector<byte> value(value_string.begin(), value_string.end());
+
+ std::size_t id = 1337;
+ std::string label = "Botan test data object";
+ std::string application = "Botan test application";
+ DataObjectProperties data_obj_props;
+ data_obj_props.set_application(application);
+ data_obj_props.set_label(label);
+ data_obj_props.set_value(value);
+ data_obj_props.set_token(true);
+ data_obj_props.set_modifiable(true);
+ data_obj_props.set_object_id(DER_Encoder().encode(id).get_contents_unlocked());
+ Object data_obj(test_session.session(), data_obj_props);
+
+ // copy created object
+ AttributeContainer copy_attributes;
+ copy_attributes.add_string(AttributeType::Label, "Botan test copied object");
+ ObjectHandle copied_obj_handle = data_obj.copy(copy_attributes);
+
+ ObjectFinder searcher(test_session.session(), copy_attributes.attributes());
+ auto search_result = searcher.find();
+ result.test_eq("one object found", search_result.size(), 1);
+
+ data_obj.destroy();
+
+ Object copied_obj(test_session.session(), copied_obj_handle);
+ copied_obj.destroy();
+ return result;
+ }
+
+class Object_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_attribute_container,
+ test_create_destroy_data_object,
+ test_get_set_attribute_values,
+ test_object_finder,
+ test_object_copy
+ };
+
+ return run_pkcs11_tests("Object", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-object", Object_Tests);
+
+/***************************** PKCS11 RSA *****************************/
+
+#if defined(BOTAN_HAS_RSA)
+
+Test::Result test_rsa_privkey_import()
+ {
+ Test::Result result("PKCS11 import RSA private key");
+
+ TestSession test_session(true);
+
+ // create private key
+ RSA_PrivateKey priv_key(Test::rng(), 2048);
+
+ // import to card
+ RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
+ props.set_pub_exponent(priv_key.get_e());
+ props.set_prime_1(priv_key.get_p());
+ props.set_prime_2(priv_key.get_q());
+ props.set_coefficient(priv_key.get_c());
+ props.set_exponent_1(priv_key.get_d1());
+ props.set_exponent_2(priv_key.get_d2());
+
+ props.set_token(true);
+ props.set_private(true);
+ props.set_decrypt(true);
+ props.set_sign(true);
+
+ PKCS11_RSA_PrivateKey pk(test_session.session(), props);
+ result.test_success("RSA private key import was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_rsa_privkey_export()
+ {
+ Test::Result result("PKCS11 export RSA private key");
+
+ TestSession test_session(true);
+
+ // create private key
+ RSA_PrivateKey priv_key(Test::rng(), 2048);
+
+ // import to card
+ RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
+ props.set_pub_exponent(priv_key.get_e());
+ props.set_prime_1(priv_key.get_p());
+ props.set_prime_2(priv_key.get_q());
+ props.set_coefficient(priv_key.get_c());
+ props.set_exponent_1(priv_key.get_d1());
+ props.set_exponent_2(priv_key.get_d2());
+
+ props.set_token(true);
+ props.set_private(true);
+ props.set_decrypt(true);
+ props.set_sign(true);
+ props.set_extractable(true);
+ props.set_sensitive(false);
+
+ PKCS11_RSA_PrivateKey pk(test_session.session(), props);
+
+ RSA_PrivateKey exported = pk.export_key();
+ result.test_success("RSA private key export was successful");
+ result.test_eq("pkcs8 private key", pk.pkcs8_private_key(), priv_key.pkcs8_private_key());
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_rsa_pubkey_import()
+ {
+ Test::Result result("PKCS11 import RSA public key");
+
+ TestSession test_session(true);
+
+ // create public key from private key
+ RSA_PrivateKey priv_key(Test::rng(), 2048);
+
+ // import to card
+ RSA_PublicKeyImportProperties props(priv_key.get_n(), priv_key.get_e());
+ props.set_token(true);
+ props.set_encrypt(true);
+ props.set_private(false);
+
+ PKCS11_RSA_PublicKey pk(test_session.session(), props);
+ result.test_success("RSA public key import was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+Test::Result test_rsa_generate_private_key()
+ {
+ Test::Result result("PKCS11 generate RSA private key");
+ TestSession test_session(true);
+
+ RSA_PrivateKeyGenerationProperties props;
+ props.set_token(true);
+ props.set_private(true);
+ props.set_sign(true);
+ props.set_decrypt(true);
+
+ PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
+ result.test_success("RSA private key generation was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+PKCS11_RSA_KeyPair generate_rsa_keypair(const TestSession& test_session)
+ {
+ RSA_PublicKeyGenerationProperties pub_props(2048UL);
+ pub_props.set_pub_exponent();
+ pub_props.set_label("BOTAN_TEST_RSA_PUB_KEY");
+ pub_props.set_token(true);
+ pub_props.set_encrypt(true);
+ pub_props.set_verify(true);
+ pub_props.set_private(false);
+
+ RSA_PrivateKeyGenerationProperties priv_props;
+ priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
+ priv_props.set_token(true);
+ priv_props.set_private(true);
+ priv_props.set_sign(true);
+ priv_props.set_decrypt(true);
+
+ return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
+ }
+
+Test::Result test_rsa_generate_key_pair()
+ {
+ Test::Result result("PKCS11 generate RSA key pair");
+ TestSession test_session(true);
+
+ PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
+ result.test_success("RSA key pair generation was successful");
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+Test::Result test_rsa_encrypt_decrypt()
+ {
+ Test::Result result("PKCS11 RSA encrypt decrypt");
+ TestSession test_session(true);
+
+ // generate key pair
+ PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
+
+ auto encrypt_and_decrypt = [&keypair, &result](const std::vector<byte>& plaintext, const std::string& padding) -> void
+ {
+ Botan::PK_Encryptor_EME encryptor(keypair.first, padding, "pkcs11");
+ auto encrypted = encryptor.encrypt(plaintext, Test::rng());
+
+ Botan::PK_Decryptor_EME decryptor(keypair.second, padding, "pkcs11");
+ auto decrypted = decryptor.decrypt(encrypted);
+
+ // some token / middlewares do not remove the padding bytes
+ decrypted.resize(plaintext.size());
+
+ result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
+ };
+
+ std::vector<byte> plaintext(256);
+ std::iota(std::begin(plaintext), std::end(plaintext), 0);
+ encrypt_and_decrypt(plaintext, "Raw");
+
+ plaintext = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x00 };
+ encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5");
+
+ encrypt_and_decrypt(plaintext, "OAEP(SHA-1)");
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+Test::Result test_rsa_sign_verify()
+ {
+ Test::Result result("PKCS11 RSA sign and verify");
+ TestSession test_session(true);
+
+ // generate key pair
+ PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
+
+ std::vector<byte> plaintext(256);
+ std::iota(std::begin(plaintext), std::end(plaintext), 0);
+
+ auto sign_and_verify = [&keypair, &plaintext, &result](const std::string& emsa, bool multipart) -> void
+ {
+ Botan::PK_Signer signer(keypair.second, emsa, Botan::IEEE_1363, "pkcs11");
+ std::vector<byte> signature;
+ if ( multipart )
+ {
+ signer.update(plaintext.data(), plaintext.size() / 2);
+ signature = signer.sign_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, Test::rng());
+ }
+ else
+ {
+ signature = signer.sign_message(plaintext, Test::rng());
+ }
+
+
+ Botan::PK_Verifier verifier(keypair.first, emsa, Botan::IEEE_1363, "pkcs11");
+ bool rsa_ok = false;
+ if ( multipart )
+ {
+ verifier.update(plaintext.data(), plaintext.size() / 2);
+ rsa_ok = verifier.verify_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, signature.data(), signature.size());
+ }
+ else
+ {
+ rsa_ok = verifier.verify_message(plaintext, signature);
+ }
+
+ result.test_eq("RSA PKCS11 sign and verify: " + emsa, rsa_ok, true);
+ };
+
+ // single-part sign
+ sign_and_verify("Raw", false);
+ sign_and_verify("EMSA3(SHA-256)", false);
+ sign_and_verify("EMSA4(SHA-256)", false);
+
+ // multi-part sign
+ sign_and_verify("EMSA3(SHA-256)", true);
+ sign_and_verify("EMSA4(SHA-256)", true);
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+class PKCS11_RSA_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_rsa_privkey_import,
+ test_rsa_pubkey_import,
+ test_rsa_privkey_export,
+ test_rsa_generate_private_key,
+ test_rsa_generate_key_pair,
+ test_rsa_encrypt_decrypt,
+ test_rsa_sign_verify
+ };
+
+ return run_pkcs11_tests("PKCS11 RSA", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-rsa", PKCS11_RSA_Tests);
+#endif
+
+/***************************** PKCS11 ECDSA *****************************/
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+Test::Result test_ecdsa_privkey_import()
+ {
+ Test::Result result("PKCS11 import ECDSA private key");
+
+ TestSession test_session(true);
+
+ // create ecdsa private key
+ ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
+ props.set_token(true);
+ props.set_private(true);
+ props.set_sign(true);
+
+ // label
+ std::string label = "Botan test ecdsa key";
+ props.set_label(label);
+
+ PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
+ result.test_success("ECDSA private key import was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdsa_privkey_export()
+ {
+ Test::Result result("PKCS11 export ECDSA private key");
+
+ TestSession test_session(true);
+
+ // create private key
+ ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
+ props.set_token(true);
+ props.set_private(true);
+ props.set_sign(true);
+ props.set_extractable(true);
+
+ // label
+ std::string label = "Botan test ecdsa key";
+ props.set_label(label);
+
+ PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
+
+ ECDSA_PrivateKey exported = pk.export_key();
+ result.test_success("ECDSA private key export was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdsa_pubkey_import()
+ {
+ Test::Result result("PKCS11 import ECDSA public key");
+
+ TestSession test_session(true);
+
+ // create ecdsa private key
+ ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PublicKeyImportProperties props(priv_key.DER_domain(), DER_Encoder().encode(EC2OSP(priv_key.public_point(),
+ PointGFp::UNCOMPRESSED), OCTET_STRING).get_contents_unlocked());
+ props.set_token(true);
+ props.set_verify(true);
+ props.set_private(false);
+
+ // label
+ std::string label = "Botan test ecdsa pub key";
+ props.set_label(label);
+
+ PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
+ result.test_success("ECDSA public key import was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdsa_pubkey_export()
+ {
+ Test::Result result("PKCS11 export ECDSA public key");
+
+ TestSession test_session(true);
+
+ // create public key from private key
+ ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PublicKeyImportProperties props(priv_key.DER_domain(), DER_Encoder().encode(EC2OSP(priv_key.public_point(),
+ PointGFp::UNCOMPRESSED), OCTET_STRING).get_contents_unlocked());
+ props.set_token(true);
+ props.set_verify(true);
+ props.set_private(false);
+
+ // label
+ std::string label = "Botan test ecdsa pub key";
+ props.set_label(label);
+
+ PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
+
+ ECDSA_PublicKey exported = pk.export_key();
+ result.test_success("ECDSA public key export was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+Test::Result test_ecdsa_generate_private_key()
+ {
+ Test::Result result("PKCS11 generate ECDSA private key");
+ TestSession test_session(true);
+
+ EC_PrivateKeyGenerationProperties props;
+ props.set_token(true);
+ props.set_private(true);
+ props.set_sign(true);
+
+ PKCS11_ECDSA_PrivateKey pk(test_session.session(),
+ EC_Group("secp256r1").DER_encode(EC_Group_Encoding::EC_DOMPAR_ENC_OID), props);
+ result.test_success("ECDSA private key generation was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(const TestSession& test_session)
+ {
+ EC_PublicKeyGenerationProperties pub_props(EC_Group("secp256r1").DER_encode(
+ EC_Group_Encoding::EC_DOMPAR_ENC_OID));
+ pub_props.set_label("BOTAN_TEST_ECDSA_PUB_KEY");
+ pub_props.set_token(true);
+ pub_props.set_verify(true);
+ pub_props.set_private(false);
+ pub_props.set_modifiable(true);
+
+ EC_PrivateKeyGenerationProperties priv_props;
+ priv_props.set_label("BOTAN_TEST_ECDSA_PRIV_KEY");
+ priv_props.set_token(true);
+ priv_props.set_private(true);
+ priv_props.set_sensitive(true);
+ priv_props.set_extractable(false);
+ priv_props.set_sign(true);
+ priv_props.set_modifiable(true);
+
+ return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
+ }
+
+Test::Result test_ecdsa_generate_keypair()
+ {
+ Test::Result result("PKCS11 generate ECDSA key pair");
+ TestSession test_session(true);
+
+ PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session);
+ result.test_success("ECDSA key pair generation was successful");
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+Test::Result test_ecdsa_sign_verify()
+ {
+ Test::Result result("PKCS11 ECDSA sign and verify");
+ TestSession test_session(true);
+
+ // generate key pair
+ PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session);
+
+ std::vector<byte> plaintext(20, 0x01);
+
+ auto sign_and_verify = [ &keypair, &plaintext, &result ](const std::string& emsa) -> void
+ {
+ Botan::PK_Signer signer(keypair.second, emsa, Botan::IEEE_1363, "pkcs11");
+ auto signature = signer.sign_message(plaintext, Test::rng());
+
+ Botan::PK_Verifier token_verifier(keypair.first, emsa, Botan::IEEE_1363, "pkcs11");
+ bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
+
+ result.test_eq("ECDSA PKCS11 sign and verify: " + emsa, ecdsa_ok, true);
+
+ Botan::PK_Verifier soft_verifier(keypair.first, emsa, Botan::IEEE_1363);
+ bool soft_ecdsa_ok = soft_verifier.verify_message(plaintext, signature);
+
+ result.test_eq("ECDSA PKCS11 verify (in software): " + emsa, soft_ecdsa_ok, true);
+ };
+
+ sign_and_verify("Raw"); // SoftHSMv2 until now only supports "Raw"
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+class PKCS11_ECDSA_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_ecdsa_privkey_import,
+ test_ecdsa_privkey_export,
+ test_ecdsa_pubkey_import,
+ test_ecdsa_pubkey_export,
+ test_ecdsa_generate_private_key,
+ test_ecdsa_generate_keypair,
+ test_ecdsa_sign_verify
+ };
+
+ return run_pkcs11_tests("PKCS11 ECDSA", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-ecdsa", PKCS11_ECDSA_Tests);
+
+/***************************** PKCS11 ECDH *****************************/
+
+Test::Result test_ecdh_privkey_import()
+ {
+ Test::Result result("PKCS11 import ECDH private key");
+
+ TestSession test_session(true);
+
+ // create ecdh private key
+ ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
+ props.set_token(true);
+ props.set_private(true);
+ props.set_derive(true);
+
+ // label
+ std::string label = "Botan test ecdh key";
+ props.set_label(label);
+
+ PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
+ result.test_success("ECDH private key import was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdh_privkey_export()
+ {
+ Test::Result result("PKCS11 export ECDH private key");
+
+ TestSession test_session(true);
+
+ // create private key
+ ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
+ props.set_token(true);
+ props.set_private(true);
+ props.set_derive(true);
+ props.set_extractable(true);
+
+ // label
+ std::string label = "Botan test ecdh key";
+ props.set_label(label);
+
+ PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
+
+ ECDH_PrivateKey exported = pk.export_key();
+ result.test_success("ECDH private key export was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdh_pubkey_import()
+ {
+ Test::Result result("PKCS11 import ECDH public key");
+
+ TestSession test_session(true);
+
+ // create ECDH private key
+ ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PublicKeyImportProperties props(priv_key.DER_domain(), DER_Encoder().encode(EC2OSP(priv_key.public_point(),
+ PointGFp::UNCOMPRESSED), OCTET_STRING).get_contents_unlocked());
+ props.set_token(true);
+ props.set_private(false);
+ props.set_derive(true);
+
+ // label
+ std::string label = "Botan test ECDH pub key";
+ props.set_label(label);
+
+ PKCS11_ECDH_PublicKey pk(test_session.session(), props);
+ result.test_success("ECDH public key import was successful");
+
+ pk.destroy();
+ return result;
+ }
+
+Test::Result test_ecdh_pubkey_export()
+ {
+ Test::Result result("PKCS11 export ECDH public key");
+
+ TestSession test_session(true);
+
+ // create public key from private key
+ ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
+ priv_key.set_parameter_encoding(EC_Group_Encoding::EC_DOMPAR_ENC_OID);
+
+ // import to card
+ EC_PublicKeyImportProperties props(priv_key.DER_domain(), DER_Encoder().encode(EC2OSP(priv_key.public_point(),
+ PointGFp::UNCOMPRESSED), OCTET_STRING).get_contents_unlocked());
+ props.set_token(true);
+ props.set_derive(true);
+ props.set_private(false);
+
+ // label
+ std::string label = "Botan test ECDH pub key";
+ props.set_label(label);
+
+ PKCS11_ECDH_PublicKey pk(test_session.session(), props);
+
+ ECDH_PublicKey exported = pk.export_key();
+ result.test_success("ECDH public key export was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+Test::Result test_ecdh_generate_private_key()
+ {
+ Test::Result result("PKCS11 generate ECDH private key");
+ TestSession test_session(true);
+
+ EC_PrivateKeyGenerationProperties props;
+ props.set_token(true);
+ props.set_private(true);
+ props.set_derive(true);
+
+ PKCS11_ECDH_PrivateKey pk(test_session.session(),
+ EC_Group("secp256r1").DER_encode(EC_Group_Encoding::EC_DOMPAR_ENC_OID), props);
+ result.test_success("ECDH private key generation was successful");
+
+ pk.destroy();
+
+ return result;
+ }
+
+PKCS11_ECDH_KeyPair generate_ecdh_keypair(const TestSession& test_session, const std::string& label)
+ {
+ EC_PublicKeyGenerationProperties pub_props(EC_Group("secp256r1").DER_encode(
+ EC_Group_Encoding::EC_DOMPAR_ENC_OID));
+ pub_props.set_label(label + "_PUB_KEY");
+ pub_props.set_token(true);
+ pub_props.set_derive(true);
+ pub_props.set_private(false);
+ pub_props.set_modifiable(true);
+
+ EC_PrivateKeyGenerationProperties priv_props;
+ priv_props.set_label(label + "_PRIV_KEY");
+ priv_props.set_token(true);
+ priv_props.set_private(true);
+ priv_props.set_sensitive(true);
+ priv_props.set_extractable(false);
+ priv_props.set_derive(true);
+ priv_props.set_modifiable(true);
+
+ return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
+ }
+
+Test::Result test_ecdh_generate_keypair()
+ {
+ Test::Result result("PKCS11 generate ECDH key pair");
+ TestSession test_session(true);
+
+ PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
+ result.test_success("ECDH key pair generation was successful");
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+
+ return result;
+ }
+
+Test::Result test_ecdh_derive()
+ {
+ Test::Result result("PKCS11 ECDH derive");
+ TestSession test_session(true);
+
+ PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
+ PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
+
+ // SoftHSMv2 only supports CKD_NULL KDF at the moment
+ Botan::PK_Key_Agreement ka(keypair.second, "Raw", "pkcs11");
+ Botan::PK_Key_Agreement kb(keypair2.second, "Raw", "pkcs11");
+
+ Botan::SymmetricKey alice_key = ka.derive_key(32, unlock(EC2OSP(keypair2.first.public_point(),
+ PointGFp::UNCOMPRESSED)));
+ Botan::SymmetricKey bob_key = kb.derive_key(32, unlock(EC2OSP(keypair.first.public_point(), PointGFp::UNCOMPRESSED)));
+
+ bool eq = alice_key == bob_key;
+ result.test_eq("same secret key derived", eq, true);
+
+ keypair.first.destroy();
+ keypair.second.destroy();
+ keypair2.first.destroy();
+ keypair2.second.destroy();
+
+ return result;
+ }
+
+class PKCS11_ECDH_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_ecdh_privkey_import,
+ test_ecdh_privkey_export,
+ test_ecdh_pubkey_import,
+ test_ecdh_pubkey_export,
+ test_ecdh_generate_private_key,
+ test_ecdh_generate_keypair,
+ test_ecdh_derive
+ };
+
+ return run_pkcs11_tests("PKCS11 ECDH", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-ecdh", PKCS11_ECDH_Tests);
+
+#endif
+
+/***************************** PKCS11 RNG *****************************/
+
+Test::Result test_rng_generate_random()
+ {
+ Test::Result result("PKCS11 RNG generate random");
+ TestSession test_session(true);
+
+ PKCS11_RNG rng(test_session.session());
+
+ std::vector<byte> random(20);
+ rng.randomize(random.data(), random.size());
+ result.test_ne("random data generated", random, std::vector<byte>(20));
+
+ return result;
+ }
+
+Test::Result test_rng_add_entropy()
+ {
+ Test::Result result("PKCS11 RNG add entropy random");
+ TestSession test_session(true);
+
+ PKCS11_RNG rng(test_session.session());
+
+ auto random = Test::rng().random_vec(20);
+ rng.add_entropy(random.data(), random.size());
+ result.test_success("entropy added");
+
+ return result;
+ }
+
+#if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
+
+Test::Result test_pkcs11_hmac_drbg()
+ {
+ Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
+ TestSession test_session(true);
+
+ HMAC_DRBG drbg(MessageAuthenticationCode::create("HMAC(SHA-512)").release(), new PKCS11_RNG(test_session.session()));
+ result.test_success("HMAC_DRBG(HMAC(SHA512)) instantiated with PKCS11_RNG");
+
+ result.test_eq("HMAC_DRBG is not seeded yet.", drbg.is_seeded(), false);
+
+ std::string personalization_string = "Botan PKCS#11 Tests";
+ std::vector<byte> personalization_data(personalization_string.begin(), personalization_string.end());
+ drbg.add_entropy(personalization_data.data(), personalization_data.size());
+
+ result.test_eq("HMAC_DRBG is seeded now", drbg.is_seeded(), true);
+
+ auto rnd_vec = drbg.random_vec(256);
+ result.test_ne("HMAC_DRBG generated a random vector", rnd_vec, std::vector<byte>(256));
+
+ return result;
+ }
+#endif
+
+class PKCS11_RNG_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_rng_generate_random
+ ,test_rng_add_entropy
+#if defined(BOTAN_HAS_HMAC_DRBG )&& defined(BOTAN_HAS_SHA2_64)
+ ,test_pkcs11_hmac_drbg
+#endif
+ };
+
+ return run_pkcs11_tests("PKCS11 RNG", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-rng", PKCS11_RNG_Tests);
+
+/***************************** PKCS11 token management *****************************/
+
+Test::Result test_set_pin()
+ {
+ Test::Result result("PKCS11 set pin");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ PKCS11::set_pin(slot, SO_PIN_SECVEC, TEST_PIN_SECVEC);
+ result.test_success("PIN set with SO_PIN to TEST_PIN");
+
+ PKCS11::set_pin(slot, SO_PIN_SECVEC, PIN_SECVEC);
+ result.test_success("PIN changed back with SO_PIN");
+
+ return result;
+ }
+
+Test::Result test_initialize()
+ {
+ Test::Result result("PKCS11 initialize token");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ PKCS11::initialize_token(slot, "Botan PKCS#11 tests", SO_PIN_SECVEC, PIN_SECVEC);
+ result.test_success("token initialized");
+
+ return result;
+ }
+
+Test::Result test_change_pin()
+ {
+ Test::Result result("PKCS11 change pin");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ PKCS11::change_pin(slot, PIN_SECVEC, TEST_PIN_SECVEC);
+ result.test_success("PIN changed with PIN to TEST_PIN");
+
+ PKCS11::change_pin(slot, TEST_PIN_SECVEC, PIN_SECVEC);
+ result.test_success("PIN changed back with TEST_PIN to PIN");
+
+ return result;
+ }
+
+Test::Result test_change_so_pin()
+ {
+ Test::Result result("PKCS11 change so_pin");
+
+ Module module(Test::pkcs11_lib());
+ std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
+ Slot slot(module, slot_vec.at(0));
+
+ PKCS11::change_so_pin(slot, SO_PIN_SECVEC, TEST_SO_PIN_SECVEC);
+ result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
+
+ PKCS11::change_so_pin(slot, TEST_SO_PIN_SECVEC, SO_PIN_SECVEC);
+ result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
+
+ return result;
+ }
+
+class PKCS11_Token_Management_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_set_pin,
+ test_initialize,
+ test_change_pin,
+ test_change_so_pin
+ };
+
+ return run_pkcs11_tests("PKCS11 token management", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-manage", PKCS11_Token_Management_Tests);
+
+/***************************** PKCS11 token management *****************************/
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+
+Test::Result test_x509_import()
+ {
+ Test::Result result("PKCS11 X509 cert import");
+
+ TestSession test_session(true);
+
+ X509_Certificate root(Test::data_file("nist_x509/test01/end.crt"));
+ X509_CertificateProperties props(DER_Encoder().encode(root.subject_dn()).get_contents_unlocked(), root.BER_encode());
+ props.set_label("Botan PKCS#11 test certificate");
+ props.set_private(false);
+ props.set_token(true);
+
+ PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
+ result.test_success("X509 certificate imported");
+
+ PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
+ result.test_eq("X509 certificate by handle", pkcs11_cert == pkcs11_cert2, true);
+
+ pkcs11_cert.destroy();
+
+ return result;
+ }
+
+class PKCS11_X509_Tests : public PKCS11_Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_x509_import
+ };
+
+ return run_pkcs11_tests("PKCS11 X509", fns);
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-x509", PKCS11_X509_Tests);
+
+#endif
+
+#endif
+
+}
+}
diff --git a/src/tests/test_pkcs11_low_level.cpp b/src/tests/test_pkcs11_low_level.cpp
new file mode 100644
index 000000000..7b18f6f8b
--- /dev/null
+++ b/src/tests/test_pkcs11_low_level.cpp
@@ -0,0 +1,852 @@
+/*
+* (C) 2016 Daniel Neus
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+#include "test_pkcs11.h"
+
+#include <string>
+#include <vector>
+#include <functional>
+#include <memory>
+#include <array>
+#include <type_traits>
+#include <map>
+
+#if defined(BOTAN_HAS_PKCS11)
+ #include <botan/p11.h>
+#endif
+
+#if defined(BOTAN_HAS_DYNAMIC_LOADER)
+ #include <botan/dyn_load.h>
+#endif
+
+namespace Botan_Tests {
+
+namespace {
+
+#if defined(BOTAN_HAS_PKCS11)
+#if defined(BOTAN_HAS_DYNAMIC_LOADER)
+
+using namespace Botan;
+using namespace PKCS11;
+
+class RAII_LowLevel
+ {
+ public:
+ RAII_LowLevel() : m_module(Test::pkcs11_lib()), m_func_list(nullptr), m_low_level(), m_session_handle(0),
+ m_is_session_open(false), m_is_logged_in(false)
+ {
+ LowLevel::C_GetFunctionList(m_module, &m_func_list);
+ m_low_level.reset(new LowLevel(m_func_list));
+
+ C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast<CK_FLAGS>(Flag::OsLockingOk), nullptr };
+
+ m_low_level->C_Initialize(&init_args);
+ }
+ ~RAII_LowLevel() BOTAN_NOEXCEPT
+ {
+
+ if(m_is_session_open)
+ {
+ if(m_is_logged_in)
+ {
+ m_low_level.get()->C_Logout(m_session_handle, nullptr);
+ }
+
+ m_low_level.get()->C_CloseSession(m_session_handle, nullptr);
+ }
+
+ m_low_level.get()->C_Finalize(nullptr, nullptr);
+ }
+
+ std::vector<SlotId> get_slots(bool token_present) const
+ {
+ std::vector<SlotId> slots;
+ m_low_level.get()->C_GetSlotList(token_present, slots);
+
+ if(slots.empty())
+ {
+ throw Exception("No slot with attached token found");
+ }
+
+ return slots;
+ }
+
+ inline SessionHandle open_session(Flags session_flags)
+ {
+ std::vector<SlotId> slots = get_slots(true);
+ m_low_level.get()->C_OpenSession(slots.at(0), session_flags, nullptr, nullptr, &m_session_handle);
+ m_is_session_open = true;
+ return m_session_handle;
+ }
+
+ inline SessionHandle open_rw_session_with_user_login()
+ {
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle handle = open_session(session_flags);
+ login(UserType::User, PIN_SECVEC);
+ return handle;
+ }
+
+ inline SessionHandle get_session_handle() const
+ {
+ if(!m_is_session_open)
+ {
+ throw Exception("no open session");
+ }
+ return m_session_handle;
+ }
+
+ inline void close_session()
+ {
+ if(!m_is_session_open)
+ {
+ throw Exception("no open session");
+ }
+
+ m_low_level.get()->C_CloseSession(m_session_handle);
+ m_is_session_open = false;
+ }
+
+ inline void login(UserType user_type, const secure_vector<byte>& pin)
+ {
+ if(!m_is_session_open)
+ {
+ throw Exception("no open session");
+ }
+
+ if(m_is_logged_in)
+ {
+ throw Exception("Already logged in");
+ }
+
+ m_low_level.get()->C_Login(m_session_handle, user_type, pin);
+ m_is_logged_in = true;
+ }
+
+ inline void logout()
+ {
+ if(!m_is_logged_in)
+ {
+ throw Exception("Not logged in");
+ }
+
+ m_low_level.get()->C_Logout(m_session_handle);
+ m_is_logged_in = false;
+ }
+
+ LowLevel* get() const
+ {
+ return m_low_level.get();
+ }
+ private:
+ Dynamically_Loaded_Library m_module;
+ FunctionListPtr m_func_list;
+ std::unique_ptr<LowLevel> m_low_level;
+ SessionHandle m_session_handle;
+ bool m_is_session_open;
+ bool m_is_logged_in;
+ };
+
+bool no_op(ReturnValue*)
+ {
+ return true;
+ }
+
+using PKCS11_BoundTestFunction = std::function<bool(ReturnValue* return_value)>;
+
+// tests all 3 variants
+Test::Result test_function(const std::string& name, const PKCS11_BoundTestFunction& test_func,
+ const std::string& revert_fn_name, const PKCS11_BoundTestFunction& revert_func,
+ bool expect_failure, ReturnValue expected_return_value)
+ {
+ std::string test_name = revert_fn_name.empty() ? "PKCS 11 low level - " + name : "PKCS 11 low level - " + name + "/" +
+ revert_fn_name;
+ Test::Result result(test_name);
+
+ // test throw variant
+ if(expect_failure)
+ {
+ result.test_throws(name + " fails as expected", [ test_func ]()
+ {
+ test_func(ThrowException);
+ });
+ }
+ else
+ {
+ test_func(ThrowException);
+ result.test_success(name + " did not throw and completed successfully");
+
+ if(!revert_fn_name.empty())
+ {
+ revert_func(ThrowException);
+ result.test_success(revert_fn_name + " did not throw and completed successfully");
+ }
+ }
+
+ // test bool return variant
+ bool success = test_func(nullptr);
+ result.test_eq(name, success, !expect_failure);
+ if(success && !revert_fn_name.empty())
+ {
+ success = revert_func(nullptr);
+ result.test_eq(revert_fn_name, success, !expect_failure);
+ }
+
+ // test ReturnValue variant
+ ReturnValue rv;
+ success = test_func(&rv);
+ result.test_eq(name, success, !expect_failure);
+ if(!expect_failure)
+ {
+ result.test_rc_ok(name, static_cast< uint32_t >(rv));
+ }
+ else
+ {
+ result.test_rc_fail(name, "return value should be: " + std::to_string(static_cast< uint32_t >(expected_return_value)),
+ static_cast< uint32_t >(rv));
+ }
+
+ if(success && !revert_fn_name.empty())
+ {
+ success = revert_func(&rv);
+ result.test_eq(revert_fn_name, success, !expect_failure);
+ result.test_rc_ok(revert_fn_name, static_cast< uint32_t >(rv));
+ }
+
+ return result;
+ }
+
+Test::Result test_function(const std::string& name, const PKCS11_BoundTestFunction& test_func,
+ bool expect_failure, ReturnValue expected_return_value)
+ {
+ return test_function(name, test_func, std::string(), no_op, expect_failure, expected_return_value);
+ }
+
+Test::Result test_function(const std::string& name, const PKCS11_BoundTestFunction& test_func)
+ {
+ return test_function(name, test_func, std::string(), no_op, false, ReturnValue::OK);
+ }
+
+Test::Result test_function(const std::string& name, const PKCS11_BoundTestFunction& test_func,
+ const std::string& revert_fn_name, const PKCS11_BoundTestFunction& revert_func)
+ {
+ return test_function(name, test_func, revert_fn_name, revert_func, false, ReturnValue::OK);
+ }
+
+Test::Result test_low_level_ctor()
+ {
+ Test::Result result("PKCS 11 low level - LowLevel ctor");
+
+ Dynamically_Loaded_Library pkcs11_module(Test::pkcs11_lib());
+ FunctionListPtr func_list(nullptr);
+ LowLevel::C_GetFunctionList(pkcs11_module, &func_list);
+
+ LowLevel p11_low_level(func_list);
+ result.test_success("LowLevel ctor does complete for valid function list");
+
+ result.test_throws("LowLevel ctor fails for invalid function list pointer", []()
+ {
+ LowLevel p11_low_level2(nullptr);
+ });
+
+ return result;
+ }
+
+Test::Result test_c_get_function_list()
+ {
+ Dynamically_Loaded_Library pkcs11_module(Test::pkcs11_lib());
+ FunctionListPtr func_list = nullptr;
+ return test_function("C_GetFunctionList", std::bind(&LowLevel::C_GetFunctionList, std::ref(pkcs11_module), &func_list,
+ std::placeholders::_1));
+ }
+
+Test::Result test_initialize_finalize()
+ {
+ Dynamically_Loaded_Library pkcs11_module(Test::pkcs11_lib());
+ FunctionListPtr func_list = nullptr;
+ LowLevel::C_GetFunctionList(pkcs11_module, &func_list);
+
+ LowLevel p11_low_level(func_list);
+
+ // setting Flag::OsLockingOk should be the normal use case
+ C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast<CK_FLAGS>(Flag::OsLockingOk), nullptr };
+
+ auto init_bind = std::bind(&LowLevel::C_Initialize, p11_low_level, &init_args, std::placeholders::_1);
+ auto finalize_bind = std::bind(&LowLevel::C_Finalize, p11_low_level, nullptr, std::placeholders::_1);
+ return test_function("C_Initialize", init_bind, "C_Finalize", finalize_bind);
+ }
+
+Test::Result test_c_get_info()
+ {
+ RAII_LowLevel p11_low_level;
+
+ Info info = {};
+ Test::Result result = test_function("C_GetInfo", std::bind(&LowLevel::C_GetInfo, *p11_low_level.get(), &info,
+ std::placeholders::_1));
+ result.test_ne("C_GetInfo crypto major version", info.cryptokiVersion.major, 0);
+
+ return result;
+ }
+
+Test::Result test_c_get_slot_list()
+ {
+ RAII_LowLevel p11_low_level;
+
+ std::vector<SlotId> slot_vec;
+
+ // assumes at least one smartcard reader is attached
+ bool token_present = false;
+
+ auto binder = std::bind(static_cast< bool (LowLevel::*)(bool, std::vector<SlotId>&, ReturnValue*) const>
+ (&LowLevel::C_GetSlotList), *p11_low_level.get(), std::ref(token_present), std::ref(slot_vec), std::placeholders::_1);
+
+ Test::Result result = test_function("C_GetSlotList", binder);
+ result.test_ne("C_GetSlotList number of slots without attached token > 0", slot_vec.size(), 0);
+
+ // assumes at least one smartcard reader with connected smartcard is attached
+ slot_vec.clear();
+ token_present = true;
+ result.merge(test_function("C_GetSlotList", binder));
+ result.test_ne("C_GetSlotList number of slots with attached token > 0", slot_vec.size(), 0);
+
+ return result;
+ }
+
+Test::Result test_c_get_slot_info()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(false);
+
+ SlotInfo slot_info = {};
+ Test::Result result = test_function("C_GetSlotInfo", std::bind(&LowLevel::C_GetSlotInfo, *p11_low_level.get(),
+ slot_vec.at(0), &slot_info, std::placeholders::_1));
+
+ std::string slot_desc(reinterpret_cast< char* >(slot_info.slotDescription));
+ result.test_ne("C_GetSlotInfo returns non empty description", slot_desc.size(), 0);
+
+ return result;
+ }
+
+Test::Result test_c_get_token_info()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ TokenInfo token_info = {};
+ Test::Result result = test_function("C_GetTokenInfo", std::bind(&LowLevel::C_GetTokenInfo, *p11_low_level.get(),
+ slot_vec.at(0), &token_info, std::placeholders::_1));
+
+ std::string serial(reinterpret_cast< char* >(token_info.serialNumber));
+ result.test_ne("C_GetTokenInfo returns non empty serial number", serial.size(), 0);
+
+ return result;
+ }
+
+Test::Result test_c_wait_for_slot_event()
+ {
+ RAII_LowLevel p11_low_level;
+
+ Flags flags = PKCS11::flags(Flag::DontBlock);
+ SlotId slot_id = 0;
+
+ return test_function("C_WaitForSlotEvent", std::bind(&LowLevel::C_WaitForSlotEvent, *p11_low_level.get(),
+ flags, &slot_id, nullptr, std::placeholders::_1), true, ReturnValue::NoEvent);
+ }
+
+Test::Result test_c_get_mechanism_list()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ std::vector<MechanismType> mechanisms;
+
+ auto binder = std::bind(static_cast< bool (LowLevel::*)(SlotId, std::vector<MechanismType>&, ReturnValue*) const>
+ (&LowLevel::C_GetMechanismList), *p11_low_level.get(), slot_vec.at(0), std::ref(mechanisms), std::placeholders::_1);
+
+ Test::Result result = test_function("C_GetMechanismList", binder);
+ result.confirm("C_GetMechanismList returns non empty mechanisms list", !mechanisms.empty());
+
+ return result;
+ }
+
+Test::Result test_c_get_mechanism_info()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ std::vector<MechanismType> mechanisms;
+ p11_low_level.get()->C_GetMechanismList(slot_vec.at(0), mechanisms);
+
+ MechanismInfo mechanism_info = {};
+ return test_function("C_GetMechanismInfo", std::bind(&LowLevel::C_GetMechanismInfo, *p11_low_level.get(),
+ slot_vec.at(0), mechanisms.at(0), &mechanism_info, std::placeholders::_1));
+ }
+
+Test::Result test_c_init_token()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ const std::string label = "Botan PKCS#11 tests";
+
+ auto sec_vec_binder = std::bind(
+ static_cast< bool (LowLevel::*)(SlotId, const secure_vector<byte>&, const std::string&, ReturnValue*) const>
+ (&LowLevel::C_InitToken<secure_allocator<byte>>), *p11_low_level.get(), slot_vec.at(0), std::ref(SO_PIN_SECVEC),
+ std::ref(label), std::placeholders::_1);
+
+ return test_function("C_InitToken", sec_vec_binder);
+ }
+
+Test::Result test_open_close_session()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ // public read only session
+ Flags flags = PKCS11::flags(Flag::SerialSession);
+ SessionHandle session_handle = 0;
+
+ auto open_session_bind = std::bind(&LowLevel::C_OpenSession, *p11_low_level.get(),
+ slot_vec.at(0), std::ref(flags), nullptr, nullptr, &session_handle, std::placeholders::_1);
+
+ auto close_session_bind = std::bind(&LowLevel::C_CloseSession, *p11_low_level.get(),
+ std::ref(session_handle), std::placeholders::_1);
+
+ Test::Result result = test_function("C_OpenSession", open_session_bind, "C_CloseSession", close_session_bind);
+
+ // public read write session
+ flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ result.merge(test_function("C_OpenSession", open_session_bind, "C_CloseSession", close_session_bind));
+
+ return result;
+ }
+
+Test::Result test_c_close_all_sessions()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ auto open_two_sessions = [ &slot_vec, &p11_low_level ]() -> void
+ {
+ // public read only session
+ Flags flags = PKCS11::flags(Flag::SerialSession);
+ SessionHandle first_session_handle = 0, second_session_handle = 0;
+
+ p11_low_level.get()->C_OpenSession(slot_vec.at(0), flags, nullptr, nullptr, &first_session_handle);
+
+ flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ p11_low_level.get()->C_OpenSession(slot_vec.at(0), flags, nullptr, nullptr, &second_session_handle);
+ };
+
+ open_two_sessions();
+
+ Test::Result result("PKCS 11 low level - C_CloseAllSessions");
+
+ // test throw variant
+ p11_low_level.get()->C_CloseAllSessions(slot_vec.at(0));
+ result.test_success("C_CloseAllSessions does not throw");
+
+ // test bool return variant
+ open_two_sessions();
+
+ bool success = p11_low_level.get()->C_CloseAllSessions(slot_vec.at(0), nullptr);
+ result.test_eq("C_CloseAllSessions", success, true);
+
+ // test ReturnValue variant
+ open_two_sessions();
+
+ ReturnValue rv = static_cast< ReturnValue >(-1);
+ success = p11_low_level.get()->C_CloseAllSessions(slot_vec.at(0), &rv);
+ result.test_eq("C_CloseAllSessions", success, true);
+ result.test_rc_ok("C_CloseAllSessions", static_cast< uint32_t >(rv));
+
+ return result;
+ }
+
+Test::Result test_c_get_session_info()
+ {
+ RAII_LowLevel p11_low_level;
+ std::vector<SlotId> slot_vec = p11_low_level.get_slots(true);
+
+ // public read only session
+ Flags flags = PKCS11::flags(Flag::SerialSession);
+ SessionHandle session_handle = p11_low_level.open_session(flags);
+
+ SessionInfo session_info = {};
+ Test::Result result = test_function("C_GetSessionInfo", std::bind(&LowLevel::C_GetSessionInfo, *p11_low_level.get(),
+ session_handle, &session_info, std::placeholders::_1));
+
+ result.confirm("C_GetSessionInfo returns same slot id as during call to C_OpenSession",
+ session_info.slotID == slot_vec.at(0));
+ result.confirm("C_GetSessionInfo returns same flags as during call to C_OpenSession", session_info.flags == flags);
+ result.confirm("C_GetSessionInfo returns public read only session state",
+ session_info.state == static_cast<CK_FLAGS>(SessionState::RoPublicSession));
+
+ return result;
+ }
+
+Test::Result login_logout_helper(const RAII_LowLevel& p11_low_level, SessionHandle handle, UserType user_type,
+ const std::string& pin)
+ {
+ secure_vector<byte> pin_as_sec_vec(pin.begin(), pin.end());
+
+ auto login_secvec_binder = std::bind(static_cast< bool (LowLevel::*)(SessionHandle, UserType,
+ const secure_vector<byte>&, ReturnValue*) const>
+ (&LowLevel::C_Login<secure_allocator<byte>>), *p11_low_level.get(),
+ handle, user_type, std::ref(pin_as_sec_vec), std::placeholders::_1);
+
+ auto logout_binder = std::bind(static_cast< bool (LowLevel::*)(SessionHandle, ReturnValue*) const>
+ (&LowLevel::C_Logout), *p11_low_level.get(), handle, std::placeholders::_1);
+
+ return test_function("C_Login", login_secvec_binder, "C_Logout", logout_binder);
+ }
+
+Test::Result test_c_login_logout_security_officier()
+ {
+ RAII_LowLevel p11_low_level;
+
+ // can only login to R/W session
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+
+ return login_logout_helper(p11_low_level, session_handle, UserType::SO, SO_PIN);
+ }
+
+Test::Result test_c_login_logout_user()
+ {
+ RAII_LowLevel p11_low_level;
+
+ // R/O session
+ Flags session_flags = PKCS11::flags(Flag::SerialSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+ Test::Result result = login_logout_helper(p11_low_level, session_handle, UserType::User, PIN);
+ p11_low_level.close_session();
+
+ // R/W session
+ session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ session_handle = p11_low_level.open_session(session_flags);
+
+ result.merge(login_logout_helper(p11_low_level, session_handle, UserType::User, PIN));
+
+ return result;
+ }
+
+Test::Result test_c_init_pin()
+ {
+ RAII_LowLevel p11_low_level;
+
+ // C_InitPIN can only be called in the "R/W SO Functions" state
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+
+ p11_low_level.login(UserType::SO, SO_PIN_SECVEC);
+
+ auto sec_vec_binder = std::bind(
+ static_cast< bool (LowLevel::*)(SessionHandle, const secure_vector<byte>&, ReturnValue*) const>
+ (&LowLevel::C_InitPIN<secure_allocator<byte>>), *p11_low_level.get(), session_handle, std::ref(PIN_SECVEC),
+ std::placeholders::_1);
+
+ return test_function("C_InitPIN", sec_vec_binder);
+ }
+
+Test::Result test_c_set_pin()
+ {
+ RAII_LowLevel p11_low_level;
+
+ // C_SetPIN can only be called in the "R / W Public Session" state, "R / W SO Functions" state, or "R / W User Functions" state
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+
+ // now we are in "R / W Public Session" state: this will change the pin of the user
+
+ auto get_pin_bind = [ &session_handle, &p11_low_level ](const secure_vector<byte>& old_pin,
+ const secure_vector<byte>& new_pin) -> PKCS11_BoundTestFunction
+ {
+ return std::bind(static_cast< bool (LowLevel::*)(SessionHandle, const secure_vector<byte>&,
+ const secure_vector<byte>&, ReturnValue*) const>
+ (&LowLevel::C_SetPIN<secure_allocator<byte>>), *p11_low_level.get(), session_handle,
+ old_pin, new_pin, std::placeholders::_1);
+ };
+
+ const std::string test_pin("654321");
+ const auto test_pin_secvec = secure_vector<byte>(test_pin.begin(), test_pin.end());
+
+ PKCS11_BoundTestFunction set_pin_bind = get_pin_bind(PIN_SECVEC, test_pin_secvec);
+ PKCS11_BoundTestFunction revert_pin_bind = get_pin_bind(test_pin_secvec, PIN_SECVEC);
+
+ Test::Result result = test_function("C_SetPIN", set_pin_bind, "C_SetPIN", revert_pin_bind);
+
+ // change pin in "R / W User Functions" state
+ p11_low_level.login(UserType::User, PIN_SECVEC);
+
+ result.merge(test_function("C_SetPIN", set_pin_bind, "C_SetPIN", revert_pin_bind));
+ p11_low_level.logout();
+
+ // change so_pin in "R / W SO Functions" state
+ const std::string test_so_pin = "87654321";
+ secure_vector<byte> test_so_pin_secvec(test_so_pin.begin(), test_so_pin.end());
+ p11_low_level.login(UserType::SO, SO_PIN_SECVEC);
+
+ PKCS11_BoundTestFunction set_so_pin_bind = get_pin_bind(SO_PIN_SECVEC, test_so_pin_secvec);
+ PKCS11_BoundTestFunction revert_so_pin_bind = get_pin_bind(test_so_pin_secvec, SO_PIN_SECVEC);
+
+ result.merge(test_function("C_SetPIN", set_so_pin_bind, "C_SetPIN", revert_so_pin_bind));
+
+ return result;
+ }
+
+// Simple data object
+ObjectClass object_class = ObjectClass::Data;
+std::string label = "A data object";
+std::string data = "Sample data";
+Bbool btrue = True;
+
+std::array<Attribute, 4> dtemplate =
+ {
+ {
+ { static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::Class), &object_class, sizeof(object_class) },
+ { static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::Token), &btrue, sizeof(btrue) },
+ { static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::Label), const_cast< char* >(label.c_str()), label.size() },
+ { static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::Value), const_cast< char* >(data.c_str()), data.size() }
+ }
+ };
+
+ObjectHandle create_simple_data_object(const RAII_LowLevel& p11_low_level)
+ {
+ ObjectHandle object_handle;
+ p11_low_level.get()->C_CreateObject(p11_low_level.get_session_handle(), dtemplate.data(), dtemplate.size(),
+ &object_handle);
+ return object_handle;
+ }
+
+Test::Result test_c_create_object_c_destroy_object()
+ {
+ RAII_LowLevel p11_low_level;
+ SessionHandle session_handle = p11_low_level.open_rw_session_with_user_login();
+
+ ObjectHandle object_handle(0);
+
+ auto create_bind = std::bind(&LowLevel::C_CreateObject, *p11_low_level.get(),
+ session_handle, dtemplate.data(), dtemplate.size(), &object_handle, std::placeholders::_1);
+
+ auto destroy_bind = std::bind(&LowLevel::C_DestroyObject, *p11_low_level.get(), session_handle,
+ std::ref(object_handle), std::placeholders::_1);
+
+ return test_function("C_CreateObject", create_bind, "C_DestroyObject", destroy_bind);
+ }
+
+Test::Result test_c_get_object_size()
+ {
+ RAII_LowLevel p11_low_level;
+
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+
+ p11_low_level.login(UserType::User, PIN_SECVEC);
+
+ ObjectHandle object_handle = create_simple_data_object(p11_low_level);
+ Ulong object_size = 0;
+
+ auto bind = std::bind(&LowLevel::C_GetObjectSize, *p11_low_level.get(),
+ session_handle, object_handle, &object_size, std::placeholders::_1);
+
+ Test::Result result = test_function("C_GetObjectSize", bind);
+ result.test_ne("Object size", object_size, 0);
+
+ // cleanup
+ p11_low_level.get()->C_DestroyObject(session_handle, object_handle);
+
+ return result;
+ }
+
+Test::Result test_c_get_attribute_value()
+ {
+ RAII_LowLevel p11_low_level;
+ SessionHandle session_handle = p11_low_level.open_rw_session_with_user_login();
+
+ ObjectHandle object_handle = create_simple_data_object(p11_low_level);
+
+ std::map < AttributeType, secure_vector<byte>> getter =
+ {
+ { AttributeType::Label, secure_vector<byte>() },
+ { AttributeType::Value, secure_vector<byte>() }
+ };
+
+ auto bind = std::bind(static_cast< bool (LowLevel::*)(SessionHandle, ObjectHandle,
+ std::map<AttributeType, secure_vector<byte>>&, ReturnValue*) const>
+ (&LowLevel::C_GetAttributeValue<secure_allocator<byte>>), *p11_low_level.get(), session_handle,
+ object_handle, std::ref(getter), std::placeholders::_1);
+
+ Test::Result result = test_function("C_GetAttributeValue", bind);
+
+ std::string _label(getter[ AttributeType::Label ].begin(), getter[ AttributeType::Label ].end());
+ std::string value(getter[ AttributeType::Value ].begin(), getter[ AttributeType::Value ].end());
+ result.test_eq("label", _label, "A data object");
+ result.test_eq("value", value, "Sample data");
+
+ // cleanup
+ p11_low_level.get()->C_DestroyObject(session_handle, object_handle);
+
+ return result;
+ }
+
+std::map < AttributeType, std::vector<byte>> get_attribute_values(const RAII_LowLevel& p11_low_level,
+ SessionHandle session_handle,
+ ObjectHandle object_handle, const std::vector<AttributeType>& attribute_types)
+ {
+ std::map < AttributeType, std::vector<byte>> received_attributes;
+
+ for(const auto& type : attribute_types)
+ {
+ received_attributes.emplace(type, std::vector<byte>());
+ }
+
+ p11_low_level.get()->C_GetAttributeValue(session_handle, object_handle, received_attributes);
+
+ return received_attributes;
+ }
+
+Test::Result test_c_set_attribute_value()
+ {
+ RAII_LowLevel p11_low_level;
+
+ Flags session_flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
+ SessionHandle session_handle = p11_low_level.open_session(session_flags);
+
+ p11_low_level.login(UserType::User, PIN_SECVEC);
+
+ ObjectHandle object_handle = create_simple_data_object(p11_low_level);
+
+ std::string new_label = "A modified data object";
+
+ std::map < AttributeType, secure_vector<byte>> new_attributes =
+ {
+ { AttributeType::Label, secure_vector<byte>(new_label.begin(), new_label.end()) }
+ };
+
+ auto bind = std::bind(static_cast< bool (LowLevel::*)(SessionHandle, ObjectHandle,
+ std::map<AttributeType, secure_vector<byte>>&, ReturnValue*) const>
+ (&LowLevel::C_SetAttributeValue<secure_allocator<byte>>), *p11_low_level.get(), session_handle,
+ object_handle, std::ref(new_attributes), std::placeholders::_1);
+
+ Test::Result result = test_function("C_SetAttributeValue", bind);
+
+ // get attributes and check if they are changed correctly
+ std::vector<AttributeType> types = { AttributeType::Label, AttributeType::Value };
+ auto received_attributes = get_attribute_values(p11_low_level, session_handle, object_handle, types);
+
+ std::string retrieved_label(received_attributes[ AttributeType::Label ].begin(),
+ received_attributes[ AttributeType::Label ].end());
+
+ result.test_eq("label", new_label, retrieved_label);
+
+ // cleanup
+ p11_low_level.get()->C_DestroyObject(session_handle, object_handle);
+
+ return result;
+ }
+
+Test::Result test_c_copy_object()
+ {
+ RAII_LowLevel p11_low_level;
+ SessionHandle session_handle = p11_low_level.open_rw_session_with_user_login();
+
+ ObjectHandle object_handle = create_simple_data_object(p11_low_level);
+ ObjectHandle copied_object_handle = 0;
+
+ std::string copied_label = "A copied data object";
+
+ Attribute copy_attribute_values = { static_cast< CK_ATTRIBUTE_TYPE >(AttributeType::Label), const_cast< char* >(copied_label.c_str()), copied_label.size() };
+
+ auto binder = std::bind(&LowLevel::C_CopyObject, *p11_low_level.get(), session_handle, object_handle,
+ &copy_attribute_values, 1, &copied_object_handle, std::placeholders::_1);
+
+ Test::Result result = test_function("C_CopyObject", binder);
+
+ // get attributes and check if its copied correctly
+ std::vector<AttributeType> types = { AttributeType::Label, AttributeType::Value };
+ auto received_attributes = get_attribute_values(p11_low_level, session_handle, copied_object_handle, types);
+
+ std::string retrieved_label(received_attributes[ AttributeType::Label ].begin(),
+ received_attributes[ AttributeType::Label ].end());
+
+ result.test_eq("label", copied_label, retrieved_label);
+
+ // cleanup
+ p11_low_level.get()->C_DestroyObject(session_handle, object_handle);
+ p11_low_level.get()->C_DestroyObject(session_handle, copied_object_handle);
+
+ return result;
+ }
+
+class LowLevelTests : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
+
+ std::vector<std::function<Test::Result()>> fns =
+ {
+ test_c_get_function_list
+ ,test_low_level_ctor
+ ,test_initialize_finalize
+ ,test_c_get_info
+ ,test_c_get_slot_list
+ ,test_c_get_slot_info
+ ,test_c_get_token_info
+ ,test_c_wait_for_slot_event
+ ,test_c_get_mechanism_list
+ ,test_c_get_mechanism_info
+ ,test_open_close_session
+ ,test_c_close_all_sessions
+ ,test_c_get_session_info
+ ,test_c_init_token
+ ,test_c_login_logout_security_officier /* only possible if token is initialized */
+ ,test_c_init_pin
+ ,test_c_login_logout_user /* only possible if token is initialized and user pin is set */
+ ,test_c_set_pin
+ ,test_c_create_object_c_destroy_object
+ ,test_c_get_object_size
+ ,test_c_get_attribute_value
+ ,test_c_set_attribute_value
+ ,test_c_copy_object
+ };
+
+ for(size_t i = 0; i != fns.size(); ++i)
+ {
+ try
+ {
+ results.push_back(fns[ i ]());
+ }
+ catch(PKCS11_ReturnError& e)
+ {
+ results.push_back(Test::Result::Failure("PKCS11 low level test " + std::to_string(i), e.what()));
+
+ if(e.get_return_value() == ReturnValue::PinIncorrect)
+ {
+ break; // Do not continue to not potentially lock the token
+ }
+ }
+ catch(std::exception& e)
+ {
+ results.push_back(Test::Result::Failure("PKCS11 low level test " + std::to_string(i), e.what()));
+ }
+ }
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("pkcs11-lowlevel", LowLevelTests);
+
+#endif
+#endif
+
+}
+}
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index a79e05aba..aae4174b9 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -254,34 +254,6 @@ bool Test::Result::test_eq(const std::string& what, bool produced, bool expected
return test_is_eq(what, produced, expected);
}
-bool Test::Result::test_rc_ok(const std::string& what, int rc)
- {
- if(rc != 0)
- {
- std::ostringstream err;
- err << m_who;
- err << " " << what;
- err << " unexpectedly failed with error code " << rc;
- return test_failure(err.str());
- }
-
- return test_success();
- }
-
-bool Test::Result::test_rc_fail(const std::string& func, const std::string& why, int rc)
- {
- if(rc == 0)
- {
- std::ostringstream err;
- err << m_who;
- err << " call to " << func << " unexpectedly succeeded";
- err << " expecting failure because " << why;
- return test_failure(err.str());
- }
-
- return test_success();
- }
-
bool Test::Result::test_rc(const std::string& func, int expected, int rc)
{
if(expected != rc)
@@ -436,17 +408,20 @@ Botan::RandomNumberGenerator* Test::m_test_rng = nullptr;
std::string Test::m_data_dir;
size_t Test::m_soak_level = 0;
bool Test::m_log_success = false;
+std::string Test::m_pkcs11_lib;
//static
void Test::setup_tests(size_t soak,
bool log_success,
const std::string& data_dir,
+ const std::string& pkcs11_lib,
Botan::RandomNumberGenerator* rng)
{
m_data_dir = data_dir;
m_soak_level = soak;
m_log_success = log_success;
m_test_rng = rng;
+ m_pkcs11_lib = pkcs11_lib;
}
//static
@@ -474,6 +449,12 @@ bool Test::log_success()
}
//static
+std::string Test::pkcs11_lib()
+ {
+ return m_pkcs11_lib;
+ }
+
+//static
Botan::RandomNumberGenerator& Test::rng()
{
if(!m_test_rng)
diff --git a/src/tests/tests.h b/src/tests/tests.h
index c7bed64d9..b52ecce0d 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -184,8 +184,40 @@ class Test
bool test_lt(const std::string& what, size_t produced, size_t expected);
bool test_gte(const std::string& what, size_t produced, size_t expected);
- bool test_rc_ok(const std::string& func, int rc);
- bool test_rc_fail(const std::string& func, const std::string& why, int rc);
+ template<typename T>
+ bool test_rc_ok(const std::string& func, T rc)
+ {
+ static_assert(std::is_integral<T>::value, "Integer required.");
+
+ if(rc != 0)
+ {
+ std::ostringstream err;
+ err << m_who;
+ err << " " << func;
+ err << " unexpectedly failed with error code " << rc;
+ return test_failure(err.str());
+ }
+
+ return test_success();
+ }
+
+ template<typename T>
+ bool test_rc_fail(const std::string& func, const std::string& why, T rc)
+ {
+ static_assert(std::is_integral<T>::value, "Integer required.");
+
+ if(rc == 0)
+ {
+ std::ostringstream err;
+ err << m_who;
+ err << " call to " << func << " unexpectedly succeeded";
+ err << " expecting failure because " << why;
+ return test_failure(err.str());
+ }
+
+ return test_success();
+ }
+
bool test_rc(const std::string& func, int expected, int rc);
#if defined(BOTAN_HAS_BIGINT)
@@ -311,10 +343,12 @@ class Test
static void setup_tests(size_t soak,
bool log_succcss,
const std::string& data_dir,
+ const std::string& pkcs11_lib,
Botan::RandomNumberGenerator* rng);
static size_t soak_level();
static bool log_success();
+ static std::string pkcs11_lib();
static const std::string& data_dir();
@@ -327,6 +361,7 @@ class Test
static Botan::RandomNumberGenerator* m_test_rng;
static size_t m_soak_level;
static bool m_log_success;
+ static std::string m_pkcs11_lib;
};
/*