From 74f32443e1f44b4168e660cb79ce31b27d4ce055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Thu, 1 Oct 2009 19:14:18 +0000 Subject: [PATCH] create and delete with certificate and key --- src/cryptoki.cxx | 37 +++++- src/cryptoki.hxx | 226 ++++++++++++++++++++++++++++-------- src/openssl.hxx | 130 +++++++++++++++++++-- test/makefile.am | 5 +- test/sharedpointer_test.cxx | 111 ++++++++++++++++++ 5 files changed, 447 insertions(+), 62 deletions(-) create mode 100644 test/sharedpointer_test.cxx diff --git a/src/cryptoki.cxx b/src/cryptoki.cxx index dbf9925..dd93deb 100644 --- a/src/cryptoki.cxx +++ b/src/cryptoki.cxx @@ -258,8 +258,43 @@ namespace cryptoki { return create(attrs); } Object Session::create(const std::string& label, - const openssl::PrivateKey& key) { + const openssl::PrivateKey& key, + const openssl::X509& cert) { + int usage(cert.keyUsageFlags()); AttributeList attrs; + attrs.push_back(Attribute(CKA_CLASS) + .from(CKO_PRIVATE_KEY)); + attrs.push_back(Attribute(CKA_TOKEN).from(TRUE)); + attrs.push_back(Attribute(CKA_PRIVATE).from(TRUE)); + attrs.push_back(Attribute(CKA_MODIFIABLE).from(TRUE)); + attrs.push_back(Attribute(CKA_LABEL, label)); + attrs.push_back(Attribute(CKA_KEY_TYPE).from(CKK_RSA)); + attrs.push_back(Attribute(CKA_ID, cert.id())); + attrs.push_back(Attribute(CKA_DERIVE).from(FALSE)); + attrs.push_back(Attribute(CKA_SUBJECT, cert.subjectDER())); + attrs.push_back(Attribute(CKA_SENSITIVE).from(TRUE)); + attrs.push_back(Attribute(CKA_SECONDARY_AUTH).from(FALSE)); + attrs.push_back(Attribute(CKA_DECRYPT) // Required by Doujak/Inverardi + .from(usage&(X509v3_KU_DATA_ENCIPHERMENT + |usage&X509v3_KU_KEY_ENCIPHERMENT) + ?TRUE:FALSE)); // instead of CKA_UNWRAP + attrs.push_back(Attribute(CKA_SIGN) + .from(usage&(X509v3_KU_DIGITAL_SIGNATURE + |X509v3_KU_NON_REPUDIATION) + ?TRUE:FALSE)); + attrs.push_back(Attribute(CKA_SIGN_RECOVER) // same as CKA_SIGN + .from(usage&(X509v3_KU_DIGITAL_SIGNATURE + |X509v3_KU_NON_REPUDIATION) + ?TRUE:FALSE)); + attrs.push_back(Attribute(CKA_EXTRACTABLE).from(FALSE)); + attrs.push_back(Attribute(CKA_MODULUS, key.modulus())); + attrs.push_back(Attribute(CKA_PUBLIC_EXPONENT, key.publicExponent())); + attrs.push_back(Attribute(CKA_PRIVATE_EXPONENT, key.privateExponent())); + attrs.push_back(Attribute(CKA_PRIME_1, key.prime1())); + attrs.push_back(Attribute(CKA_PRIME_2, key.prime2())); + attrs.push_back(Attribute(CKA_EXPONENT_1, key.exponent1())); + attrs.push_back(Attribute(CKA_EXPONENT_2, key.exponent2())); + attrs.push_back(Attribute(CKA_COEFFICIENT, key.coefficient())); return create(attrs); } Object Session::create(const std::string& label, diff --git a/src/cryptoki.hxx b/src/cryptoki.hxx index fa617a1..2026c23 100644 --- a/src/cryptoki.hxx +++ b/src/cryptoki.hxx @@ -35,6 +35,119 @@ //! @see gcryptoki namespace cryptoki { + //! @todo copy in own library + /*! Inherit from SmartResource, + and overwrite free(). You must call destruct() in your destructor. */ + class SmartResource { + public: + SmartResource(): _cnt(0), _destructed(false) { + incr(); + } + //! must be called in copy constructor of children! + SmartResource(const SmartResource& o): _cnt(o._cnt), _destructed(false) { + incr(); + } + ~SmartResource() { + assert(_destructed); // child must call destruct() in destructor + } + //! must be called in assignment constructor of children! + SmartResource& operator=(const SmartResource& o) { + decr(); + _cnt = o._cnt; + incr(); + return *this; + } + protected: + //! Overwrite to free your resource. + virtual void free() = 0; + //! You must call it in your destructor! + void destruct() { + if (_destructed) return; // only once + decr(); + _destructed = true; + } + //! Seldom needed, mostly automatic. + void incr() { + if (!_cnt) _cnt = new unsigned int(0); + ++*_cnt; + assert(_cnt); + } + //! Seldom needed, mostly automatic. + void decr() { + if (!_cnt || --*_cnt) return; + delete _cnt; _cnt = 0; + free(); + } + //! Seldom needed, mostly automatic. + /*! Used in complete reassign of resource from outside. + Call incr() after assignment. */ + void clear() { + decr(); + _cnt = 0; + } + //! Reads the internal counter (for testing and debugging only); + int cnt() { + assert(_cnt); + return *_cnt; + } + private: + unsigned int *_cnt; + bool _destructed; + }; + + template class SharedPointer: public SmartResource { + public: + SharedPointer(): _p(0) {} + SharedPointer(const SharedPointer& o): SmartResource(o), _p(o._p) {} + SharedPointer(T* p): _p(p) {} + SharedPointer& operator=(const SharedPointer& o) { + return reset(o); + } + SharedPointer& operator=(T* p) { + return reset(p); + } + ~SharedPointer() { + destruct(); + } + T* const operator->() { + return get(); + } + const T* const operator->() const { + return get(); + } + const T& operator*() const { + return *get(); + } + T& operator*() { + return *get(); + } + SharedPointer& reset(const SharedPointer& o) { + SmartResource::operator=(o); + _p = o._p; + return *this; + } + SharedPointer& reset(T* p = 0) { + clear(); + _p = p; + incr(); + return *this; + } + const T* const get() const { + assert(_p); + return _p; + } + T* const get() { + assert(_p); + return _p; + } + protected: + void free() { + delete _p; _p=0; + } + private: + T* _p; + }; + #ifndef CRYPTOKI_FN_LOG #if __GNUC__ >= 2 #define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \ @@ -816,7 +929,7 @@ namespace cryptoki { //! Session Management //! Not implemented: CK_RV C_CloseAllSessions(CK_SLOT_ID); - class Session { + class Session: public SmartResource { private: friend class Login; @@ -827,8 +940,6 @@ namespace cryptoki { CK_RV _res; Session(); // forbidden - Session(const Session&); // forbidden - Session& operator=(const Session&); // forbidden bool check(CK_RV result, const std::string& context="") { _res = result; @@ -840,6 +951,18 @@ namespace cryptoki { return _res==CKR_OK; } + void free() { + try { + //! closes login. + _login.reset(); + //! calls @c C_CloseSession + check(_slot._init->_fn->C_CloseSession(_session), + CRYPTOKI_FN_LOG("C_CloseSession")); + } catch (...) { + if (!std::uncaught_exception()) throw; + } + } + public: //! Opens a new session. @@ -854,20 +977,20 @@ namespace cryptoki { //! @todo pass parameter } - //! Closes actual session + Session(const Session& o): + SmartResource(o), + _slot(o._slot), _session(o._session), _res(o._res) { + } + ~Session() { - try { - _login.reset(); - } catch (...) { - if (!std::uncaught_exception()) throw; - } - try { - //! calls @c C_CloseSession - check(_slot._init->_fn->C_CloseSession(_session), - CRYPTOKI_FN_LOG("C_CloseSession")); - } catch (...) { - if (!std::uncaught_exception()) throw; - } + destruct(); + } + + Session& operator=(const Session& o) { + SmartResource::operator=(o); + _slot = o._slot; + _session = o._session; + _res = o._res; } /*! @name Comfortable Access @@ -882,7 +1005,8 @@ namespace cryptoki { //! Create a new Certificate Object. Object create(const std::string& label, const openssl::X509& cert); //! Create a new PrivateKey Object. - Object create(const std::string& label, const openssl::PrivateKey& key); + Object create(const std::string& label, const openssl::PrivateKey& key, + const openssl::X509& cert); //! Create a new Certificate and optional PrivateKey Object. Object create(const std::string& label, const openssl::PKCS12& p12); @@ -1184,12 +1308,12 @@ namespace cryptoki { }; void login(const std::string& pin, CK_USER_TYPE userType=CKU_USER) { - _login = std::auto_ptr(new Login(*this, pin, userType)); + _login = SharedPointer(new Login(*this, pin, userType)); } void logout() { _login.reset(); } - std::auto_ptr _login; + SharedPointer _login; /*! @todo Not implemented: @code @@ -1320,12 +1444,12 @@ namespace cryptoki { friend class Session; CK_OBJECT_HANDLE _object; - Session* _session; + Session _session; CK_RV _res; bool check(CK_RV result, const std::string& context="") { _res = result; - if (_session->_slot._init->_exc && !*this) + if (_session._slot._init->_exc && !*this) if (!context.empty()) throw access_error(context+": "+error()); else @@ -1336,8 +1460,8 @@ namespace cryptoki { Object() { } - Object(Session& session, CK_OBJECT_HANDLE obj): - _session(&session), _object(obj), _res(CKR_OK) { + Object(const Session& session, CK_OBJECT_HANDLE obj): + _session(session), _object(obj), _res(CKR_OK) { } public: @@ -1364,7 +1488,7 @@ namespace cryptoki { /*! @return error text of last cryptoki call */ std::string error() { - return _session->_slot._init->error(_res); + return _session._slot._init->error(_res); } //@} @@ -1379,7 +1503,7 @@ namespace cryptoki { @code bool copyobject() { //! calls @c C_CopyObject - return check(_session->_slot._init->_fn->C_CopyObject(_session->_session, CK_OBJECT_HANDLE, + return check(_session._slot._init->_fn->C_CopyObject(_session._session, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_CopyObject")); } @@ -1391,8 +1515,8 @@ namespace cryptoki { type, param.begin().operator->(), param.size() }; //! calls @c C_DecryptInit - return check(_session->_slot._init->_fn->C_DecryptInit - (_session->_session, &mech, _object), + return check(_session._slot._init->_fn->C_DecryptInit + (_session._session, &mech, _object), CRYPTOKI_FN_LOG("C_DecryptInit")); } @@ -1401,7 +1525,7 @@ namespace cryptoki { @code bool derivekey() { //! calls @c C_DeriveKey - return check(_session->_slot._init->_fn->C_DeriveKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session._slot._init->_fn->C_DeriveKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_DeriveKey")); } @@ -1409,8 +1533,8 @@ namespace cryptoki { bool destroy() { //! calls @c C_DestroyObject - return check(_session->_slot._init->_fn->C_DestroyObject - (_session->_session, _object), + return check(_session._slot._init->_fn->C_DestroyObject + (_session._session, _object), CRYPTOKI_FN_LOG("C_DestroyObject")); } @@ -1419,7 +1543,7 @@ namespace cryptoki { @code bool digestkey() { //! calls @c C_DigestKey - return check(_session->_slot._init->_fn->C_DigestKey(_session->_session, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_DigestKey(_session._session, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_DigestKey")); } @endcode */ @@ -1429,7 +1553,7 @@ namespace cryptoki { @code bool encryptinit() { //! calls @c C_EncryptInit - return check(_session->_slot._init->_fn->C_EncryptInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_EncryptInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_EncryptInit")); } @endcode */ @@ -1439,7 +1563,7 @@ namespace cryptoki { @code bool generatekey() { //! calls @c C_GenerateKey - return check(_session->_slot._init->_fn->C_GenerateKey(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + return check(_session._slot._init->_fn->C_GenerateKey(_session._session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_GenerateKey")); } @@ -1450,7 +1574,7 @@ namespace cryptoki { @code bool generatekeypair() { //! calls @c C_GenerateKeyPair - return check(_session->_slot._init->_fn->C_GenerateKeyPair(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + return check(_session._slot._init->_fn->C_GenerateKeyPair(_session._session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_GenerateKeyPair")); @@ -1468,8 +1592,8 @@ namespace cryptoki { Attribute res; CK_ATTRIBUTE attr((CK_ATTRIBUTE){a, 0, 0}); //! calls @c C_GetAttributeValue - if (!check(_session->_slot._init->_fn->C_GetAttributeValue - (_session->_session, _object, &attr, 1), + if (!check(_session._slot._init->_fn->C_GetAttributeValue + (_session._session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue")) || !(long)attr.ulValueLen>0l) //! Without exception handling, size and type must be checked too. @@ -1477,8 +1601,8 @@ namespace cryptoki { try { attr.pValue = malloc(attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); - if (check(_session->_slot._init->_fn->C_GetAttributeValue - (_session->_session, _object, &attr, 1), + if (check(_session._slot._init->_fn->C_GetAttributeValue + (_session._session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue"))) /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open Cryptoki. From the Specs: «In the special case @@ -1592,8 +1716,8 @@ namespace cryptoki { attr = (CK_ATTRIBUTE){*it, 0, 0}; try { //! calls @c C_GetAttributeValue - if (_session->_slot._init->_fn->C_GetAttributeValue - (_session->_session, _object, &attr, 1) + if (_session._slot._init->_fn->C_GetAttributeValue + (_session._session, _object, &attr, 1) == CKR_ATTRIBUTE_TYPE_INVALID || _res == CKR_ATTRIBUTE_SENSITIVE) { continue; //! Ignores unsupported Attributes. @@ -1602,8 +1726,8 @@ namespace cryptoki { if ((long)attr.ulValueLen>0l) { attr.pValue = malloc(attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); - if (check(_session->_slot._init->_fn->C_GetAttributeValue - (_session->_session, _object, &attr, 1), + if (check(_session._slot._init->_fn->C_GetAttributeValue + (_session._session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue"))) /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open Cryptoki. From the Specs: «In the special @@ -1663,7 +1787,7 @@ namespace cryptoki { @code bool getobjectsize() { //! calls @c C_GetObjectSize - return check(_session->_slot._init->_fn->C_GetObjectSize(_session->_session, CK_OBJECT_HANDLE, CK_ULONG_PTR), + return check(_session._slot._init->_fn->C_GetObjectSize(_session._session, CK_OBJECT_HANDLE, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_GetObjectSize")); } @endcode */ @@ -1673,7 +1797,7 @@ namespace cryptoki { @code bool setattributevalue() { //! calls @c C_SetAttributeValue - return check(_session->_slot._init->_fn->C_SetAttributeValue(_session->_session, CK_OBJECT_HANDLE, + return check(_session._slot._init->_fn->C_SetAttributeValue(_session._session, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_SetAttributeValue")); } @@ -1683,7 +1807,7 @@ namespace cryptoki { @code bool setoperationstate() { //! calls @c C_SetOperationState - return check(_session->_slot._init->_fn->C_SetOperationState(_session->_session, CK_BYTE_PTR, CK_ULONG, + return check(_session._slot._init->_fn->C_SetOperationState(_session._session, CK_BYTE_PTR, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_SetOperationState")); } @@ -1693,7 +1817,7 @@ namespace cryptoki { @code bool signinit() { //! calls @c C_SignInit - return check(_session->_slot._init->_fn->C_SignInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_SignInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_SignInit")); } @endcode */ @@ -1703,7 +1827,7 @@ namespace cryptoki { @code bool signrecoverinit() { //! calls @c C_SignRecoverInit - return check(_session->_slot._init->_fn->C_SignRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_SignRecoverInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_SignRecoverInit")); } @endcode */ @@ -1712,7 +1836,7 @@ namespace cryptoki { @code bool unwrapkey() { //! calls @c C_UnwrapKey - return check(_session->_slot._init->_fn->C_UnwrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session._slot._init->_fn->C_UnwrapKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_UnwrapKey")); @@ -1723,7 +1847,7 @@ namespace cryptoki { @code bool verifyinit() { //! calls @c C_VerifyInit - return check(_session->_slot._init->_fn->C_VerifyInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_VerifyInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_VerifyInit")); } @endcode */ @@ -1733,7 +1857,7 @@ namespace cryptoki { @code bool verifyrecoverinit() { //! calls @c C_VerifyRecoverInit - return check(_session->_slot._init->_fn->C_VerifyRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session._slot._init->_fn->C_VerifyRecoverInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_VerifyRecoverInit")); } @endcode */ @@ -1743,7 +1867,7 @@ namespace cryptoki { @code bool wrapkey() { //! calls @c C_WrapKey - return check(_session->_slot._init->_fn->C_WrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session._slot._init->_fn->C_WrapKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_WrapKey")); } diff --git a/src/openssl.hxx b/src/openssl.hxx index 529f2e0..b8047be 100644 --- a/src/openssl.hxx +++ b/src/openssl.hxx @@ -16,8 +16,10 @@ #include #include // BASIC_CONSTRAINTS +#include #include #include +#include /*! @defgroup gopenssl C++ Wrapper around OpenSSL API */ //@{ @@ -67,6 +69,13 @@ namespace openssl { } }; //---------------------------------------------------------------------------- + class key_error: public openssl_error { + public: + key_error(const std::string& reason) throw(): + openssl_error("private key: "+reason) { + } + }; + //---------------------------------------------------------------------------- class bio_error: public openssl_error { public: bio_error(const std::string& reason) throw(): @@ -116,6 +125,20 @@ namespace openssl { } }; //---------------------------------------------------------------------------- + class key_copy_failed: public key_error { + public: + key_copy_failed() throw(): + key_error("key object copy failed") { + } + }; + //---------------------------------------------------------------------------- + class undefined_key: public key_error { + public: + undefined_key() throw(): + key_error("private key must not be 0") { + } + }; + //---------------------------------------------------------------------------- class pkcs12_reading_failed: public pkcs12_error { public: pkcs12_reading_failed(const std::string& file) throw(): @@ -368,14 +391,20 @@ namespace openssl { M_ASN1_STRING_length(cn)); } //! Get key usage flags. - std::string keyUsageFlags() const { + int keyUsageFlags() const { + int res(X509v3_KU_UNDEF); int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1)); if (pos>=0) { ASN1_BIT_STRING* ku((ASN1_BIT_STRING*)X509V3_EXT_d2i (X509_get_ext(_x509, pos))); - return std::string((char*)M_ASN1_STRING_data(ku), - M_ASN1_STRING_length(ku)); - } else return std::string(); //! @todo better throw exception? + std::string val((char*)M_ASN1_STRING_data(ku), + M_ASN1_STRING_length(ku)); + if (val.size()<=sizeof(int)) + val = std::string(sizeof(int)-val.size(), '\0')+val; + assert(val.size()==sizeof(int)); + res = *((int*)val.begin().operator->()); + } + return res; } private: ::X509* _x509; @@ -384,8 +413,91 @@ namespace openssl { //============================================================================ class PrivateKey { public: - PrivateKey(EVP_PKEY *) { + PrivateKey(): _key(EVP_PKEY_new()) { + if (!_key) throw allocation_failed(); + } + PrivateKey(const PrivateKey& o): _key(0) { + copy(o); + } + PrivateKey(EVP_PKEY* k): _key(k) { + if (!_key) throw undefined_key(); + } + ~PrivateKey() { + EVP_PKEY_free(_key); + } + PrivateKey& operator=(const PrivateKey& o) { + copy(o); + return *this; + } + std::string modulus() const { + return string(rsa()->n); + } + std::string publicExponent() const { + return string(rsa()->e); + } + std::string privateExponent() const { + return string(rsa()->d); + } + std::string prime1() const { + return string(rsa()->p); + } + std::string prime2() const { + return string(rsa()->q); + } + std::string exponent1() const { + return string(rsa()->dmp1); + } + std::string exponent2() const { + return string(rsa()->dmq1); + } + std::string coefficient() const { + return string(rsa()->iqmp); + } + private: + void copy(const PrivateKey& o) { + EVP_PKEY_free(_key); + if (!(_key=EVP_PKEY_new())) throw allocation_failed(); + rsa(o); + dsa(o); + dh(o); + ec(o); + } + std::string string(BIGNUM* a) const { + std::string res(BN_num_bytes(a), '0'); + BN_bn2bin(a, (unsigned char*)res.begin().operator->()); + return res; + } + void rsa(const PrivateKey& o) { + //! @todo throw exception if 0? + RSA* tmp(o.rsa()); + if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed(); + } + void dsa(const PrivateKey& o) { + DSA* tmp(o.dsa()); + if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed(); + } + void dh(const PrivateKey& o) { + DH* tmp(o.dh()); + if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed(); + } + void ec(const PrivateKey& o) { + EC_KEY* tmp(o.ec()); + if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed(); + } + RSA* rsa() const { + //! @todo throw exception if 0? + return EVP_PKEY_get1_RSA(_key); + } + DSA* dsa() const { + return EVP_PKEY_get1_DSA(_key); + } + DH* dh() const { + return EVP_PKEY_get1_DH(_key); + } + EC_KEY* ec() const { + return EVP_PKEY_get1_EC_KEY(_key); } + EVP_PKEY* _key; }; //============================================================================ @@ -430,20 +542,20 @@ namespace openssl { delete *it; } - bool hasPrivateKey() { + bool hasPrivateKey() const { return _key; } - bool hasCert() { + bool hasCert() const { return _cert; } - const PrivateKey& privateKey() { + const PrivateKey& privateKey() const { if (!_key) throw pkcs12_no_private_key(); return *_key; }; - const X509& x509() { + const X509& x509() const { if (!_cert) throw pkcs12_no_x509(); return *_cert; }; diff --git a/test/makefile.am b/test/makefile.am index 127350c..0134a36 100644 --- a/test/makefile.am +++ b/test/makefile.am @@ -7,8 +7,11 @@ AM_CXXFLAGS += -I ${top_srcdir}/src AM_LDFLAGS = -L${top_builddir}/src LDADD = -lcppunit -check_PROGRAMS= +check_PROGRAMS = sharedpointer_test TESTS=${check_PROGRAMS} +sharedpointer_test_SOURCES = sharedpointer_test.cxx +sharedpointer_test_LDFLAGS = -lcryptoki++ + CLEANFILES = MAINTAINERCLEANFILES = makefile.in diff --git a/test/sharedpointer_test.cxx b/test/sharedpointer_test.cxx new file mode 100644 index 0000000..a25d579 --- /dev/null +++ b/test/sharedpointer_test.cxx @@ -0,0 +1,111 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +#include +#include +#include +#include +#include +#include +#include + +using namespace cryptoki; + +template class SharedPointerInside: public SharedPointer { + public: + SharedPointerInside() {} + SharedPointerInside(const SharedPointerInside& o): + SharedPointer(o) {} + SharedPointerInside(T* p): SharedPointer(p) {} + ~SharedPointerInside() { + SmartResource::destruct(); + } + SharedPointerInside& operator=(const SharedPointerInside& o) { + return reset(o), *this; + } + SharedPointerInside& operator=(T* p) { + return reset(p), *this; + } + int cnt() { + return SharedPointer::cnt(); + } + static int freed() { + return _free; + } + protected: + void free() { + ++_free; + SharedPointer::free(); + } + private: + static int _free; +}; + +template int SharedPointerInside::_free(0); + +class SharedPointerTest: public CppUnit::TestFixture { + public: + void check() { + { + SharedPointerInside i, j(new int); + CPPUNIT_ASSERT_EQUAL(0, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(1, i.cnt()); + CPPUNIT_ASSERT_EQUAL(1, j.cnt()); + i = j; + CPPUNIT_ASSERT_EQUAL(1, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(i.get(), j.get()); + CPPUNIT_ASSERT_EQUAL(2, i.cnt()); + CPPUNIT_ASSERT_EQUAL(2, j.cnt()); + *i = 5; + CPPUNIT_ASSERT_EQUAL(1, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(5, *j); + CPPUNIT_ASSERT_EQUAL(2, i.cnt()); + CPPUNIT_ASSERT_EQUAL(2, j.cnt()); + int* old(j.get()); + i = new int(6); + CPPUNIT_ASSERT_EQUAL(1, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(5, *j); + CPPUNIT_ASSERT_EQUAL(6, *i); + CPPUNIT_ASSERT(i.get()!=j.get()); + CPPUNIT_ASSERT_EQUAL(1, i.cnt()); + CPPUNIT_ASSERT_EQUAL(1, j.cnt()); + i = new int(8); + CPPUNIT_ASSERT_EQUAL(2, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(5, *j); + CPPUNIT_ASSERT_EQUAL(8, *i); + CPPUNIT_ASSERT(i.get()!=j.get()); + CPPUNIT_ASSERT_EQUAL(1, i.cnt()); + CPPUNIT_ASSERT_EQUAL(1, j.cnt()); + { + SharedPointerInside k(j); + CPPUNIT_ASSERT_EQUAL(1, i.cnt()); + CPPUNIT_ASSERT_EQUAL(2, j.cnt()); + CPPUNIT_ASSERT_EQUAL(2, k.cnt()); + } + CPPUNIT_ASSERT_EQUAL(2, SharedPointerInside::freed()); + CPPUNIT_ASSERT_EQUAL(1, i.cnt()); + CPPUNIT_ASSERT_EQUAL(1, j.cnt()); + } + CPPUNIT_ASSERT_EQUAL(4, SharedPointerInside::freed()); + } + CPPUNIT_TEST_SUITE(SharedPointerTest); + CPPUNIT_TEST(check); + CPPUNIT_TEST_SUITE_END(); + +}; +CPPUNIT_TEST_SUITE_REGISTRATION(SharedPointerTest); + +int main(int argc, char** argv) try { + std::ofstream ofs((*argv+std::string(".xml")).c_str()); + CppUnit::TextUi::TestRunner runner; + runner.setOutputter(new CppUnit::XmlOutputter(&runner.result(), ofs)); + runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); + return runner.run() ? 0 : 1; + } catch (std::exception& e) { + std::cerr<<"***Exception: "<