diff options
37 files changed, 9857 insertions, 55 deletions
diff --git a/configure.py b/configure.py index 08babc978..833aaf1aa 100755 --- a/configure.py +++ b/configure.py @@ -308,6 +308,9 @@ def process_command_line(args): build_group.add_option('--with-build-dir', metavar='DIR', default='', help='setup the build in DIR') + build_group.add_option('--with-external-includedir', metavar='DIR', default='', + help='use DIR for external includes') + link_methods = ['symlink', 'hardlink', 'copy'] build_group.add_option('--link-method', default=None, metavar='METHOD', choices=link_methods, @@ -1176,16 +1179,30 @@ def gen_makefile_lists(var, build_config, options, modules, cc, arch, osinfo): Form snippets of makefile for building each source file """ def build_commands(sources, obj_dir, flags): - for (obj_file,src) in zip(objectfile_list(sources, obj_dir), sources): - yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s%s %s %s %s$@\n' % ( - obj_file, src, - isa_specific_flags(cc, src), - flags, - cc.add_include_dir_option, - build_config.include_dir, - cc.compile_flags, - src, - cc.output_to_option) + if options.with_external_includedir: + for (obj_file,src) in zip(objectfile_list(sources, obj_dir), sources): + yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s%s %s%s %s %s %s$@\n' % ( + obj_file, src, + isa_specific_flags(cc, src), + flags, + cc.add_include_dir_option, + build_config.include_dir, + cc.add_include_dir_option, + options.with_external_includedir, + cc.compile_flags, + src, + cc.output_to_option) + else: + for (obj_file,src) in zip(objectfile_list(sources, obj_dir), sources): + yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s%s %s %s %s$@\n' % ( + obj_file, src, + isa_specific_flags(cc, src), + flags, + cc.add_include_dir_option, + build_config.include_dir, + cc.compile_flags, + src, + cc.output_to_option) for t in ['lib', 'cli', 'test']: @@ -1332,7 +1349,7 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'visibility_attribute': cc.gen_visibility_attribute(options), # 'botan' or 'botan-1.11'. Used in Makefile and install script - # This can be made constistent over all platforms in the future + # This can be made consistent over all platforms in the future 'libname': 'botan' if options.os == 'windows' else 'botan-%d.%d' % (build_config.version_major, build_config.version_minor), 'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options), 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, + ©_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; }; /* |