diff options
Diffstat (limited to 'src/lib/prov/pkcs11/p11_object.h')
-rw-r--r-- | src/lib/prov/pkcs11/p11_object.h | 743 |
1 files changed, 743 insertions, 0 deletions
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 |