bug fixes and reference counters (prevents hanging); refs #28
This commit is contained in:
		| @@ -170,7 +170,7 @@ namespace cardos { | |||||||
|         _tag = content[0]; |         _tag = content[0]; | ||||||
|         _length = content[1]; |         _length = content[1]; | ||||||
|         _value = content.substr(2, _length); |         _value = content.substr(2, _length); | ||||||
|         if (_length+2>content.size()) |         if (std::string::size_type(_length)+2>content.size()) | ||||||
|           throw wrong_dataformat(content, "not a BER, content size too" |           throw wrong_dataformat(content, "not a BER, content size too" | ||||||
|                                  " small: \""+crypto::binToHex(_value)+"\""); |                                  " small: \""+crypto::binToHex(_value)+"\""); | ||||||
|         if (tagType()==END_OF_CONTENT) return; // done |         if (tagType()==END_OF_CONTENT) return; // done | ||||||
|   | |||||||
| @@ -114,7 +114,7 @@ namespace crypto { | |||||||
|     if (!data.size()) |     if (!data.size()) | ||||||
|       return "<empty>"; |       return "<empty>"; | ||||||
|     else if (data.find_first_not_of(VALID_CHARS)<data.size()) |     else if (data.find_first_not_of(VALID_CHARS)<data.size()) | ||||||
|       return hexTxt(data); |       return hexTxt(data, len); | ||||||
|     else |     else | ||||||
|       return "\""+data+"\""; |       return "\""+data+"\""; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -277,9 +277,9 @@ namespace cryptoki { | |||||||
|  |  | ||||||
| //   //! Map Attribute Class to type | //   //! Map Attribute Class to type | ||||||
| //   /*! @todo to be completed ... */ | //   /*! @todo to be completed ... */ | ||||||
| //   #define CRYPTOKI_DECLARE_ATTR(ATTR_ID, TYPE) \ | //   #define CRYPTOKI_DECLARE_ATTR(ATTR_ID, TYPE) \//  | ||||||
| //     template<> class AttributeType<ATTR_ID> { \ | //     template<> class AttributeType<ATTR_ID> { \//  | ||||||
| //       public: typedef TYPE Type; \ | //       public: typedef TYPE Type; \//  | ||||||
| //     } | //     } | ||||||
| //   template<CK_ATTRIBUTE_TYPE Attribute> class AttributeType {}; | //   template<CK_ATTRIBUTE_TYPE Attribute> class AttributeType {}; | ||||||
| //   CRYPTOKI_DECLARE_ATTR(CKA_CLASS, CK_OBJECT_CLASS); | //   CRYPTOKI_DECLARE_ATTR(CKA_CLASS, CK_OBJECT_CLASS); | ||||||
| @@ -611,6 +611,8 @@ namespace cryptoki { | |||||||
|   /// Load Cryptoki Library for use with Smart Card. |   /// Load Cryptoki Library for use with Smart Card. | ||||||
|   class Library { |   class Library { | ||||||
|  |  | ||||||
|  |       friend class Slot; | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|       //! Initialize for a given library (default cryptoki) |       //! Initialize for a given library (default cryptoki) | ||||||
| @@ -623,6 +625,12 @@ namespace cryptoki { | |||||||
|           _init(library, exc) { |           _init(library, exc) { | ||||||
|         CRYPTOLOG("log"); |         CRYPTOLOG("log"); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |     protected: | ||||||
|  |        | ||||||
|  |       Library() { | ||||||
|  |         CRYPTOLOG("log"); | ||||||
|  |       } | ||||||
|        |        | ||||||
|     public: |     public: | ||||||
|        |        | ||||||
| @@ -778,13 +786,27 @@ namespace cryptoki { | |||||||
|         CRYPTOLOG("ID="<<_slot); |         CRYPTOLOG("ID="<<_slot); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       Slot(): _slot(0), _res(-1) { | ||||||
|  |         CRYPTOLOG("ID="<<_slot); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       Slot& operator=(const Slot& o) { | ||||||
|  |         _library = o._library; | ||||||
|  |         _slot = o._slot; | ||||||
|  |         _res = o._res; | ||||||
|  |         CRYPTOLOG("ID="<<_slot); | ||||||
|  |         return *this; | ||||||
|  |       } | ||||||
|  |  | ||||||
|       bool check(CK_RV result, const std::string& context="") { |       bool check(CK_RV result, const std::string& context="") { | ||||||
|         _res = result; |         _res = result; | ||||||
|         if (_library.exc() && !*this) |         if (_library.exc() && !*this) { | ||||||
|           if (!context.empty()) |           if (!context.empty()) { | ||||||
|             throw access_error(context+": "+error()); |             throw access_error(context+": "+error()); | ||||||
|           else |           } else { | ||||||
|             throw access_error(error()); |             throw access_error(error()); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|         return _res==CKR_OK; |         return _res==CKR_OK; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -940,11 +962,13 @@ namespace cryptoki { | |||||||
|  |  | ||||||
|       bool check(CK_RV result, const std::string& context="") { |       bool check(CK_RV result, const std::string& context="") { | ||||||
|         _res = result; |         _res = result; | ||||||
|         if (_slot._library.exc() && !*this) |         if (_slot._library.exc() && !*this) { | ||||||
|           if (!context.empty()) |           if (!context.empty()) { | ||||||
|             throw access_error(context+": "+error()); |             throw access_error(context+": "+error()); | ||||||
|           else |           } else { | ||||||
|             throw access_error(error()); |             throw access_error(error()); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|         return _res==CKR_OK; |         return _res==CKR_OK; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1343,11 +1367,13 @@ namespace cryptoki { | |||||||
|  |  | ||||||
|       bool check(CK_RV result, const std::string& context="") { |       bool check(CK_RV result, const std::string& context="") { | ||||||
|         _res = result; |         _res = result; | ||||||
|         if (_session._slot._library.exc() && !*this) |         if (_session._slot._library.exc() && !*this) { | ||||||
|           if (!context.empty()) |           if (!context.empty()) { | ||||||
|             throw access_error(context+": "+error()); |             throw access_error(context+": "+error()); | ||||||
|           else |           } else { | ||||||
|             throw access_error(error()); |             throw access_error(error()); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|         return _res==CKR_OK; |         return _res==CKR_OK; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1282,7 +1282,7 @@ namespace openssl { | |||||||
|  |  | ||||||
|       operator bool() const { |       operator bool() const { | ||||||
|         CRYPTOLOG("log"); |         CRYPTOLOG("log"); | ||||||
|         return _bio>0; |         return _bio; | ||||||
|       } |       } | ||||||
|        |        | ||||||
|       TCP& operator>>(std::string& s) { |       TCP& operator>>(std::string& s) { | ||||||
| @@ -1302,7 +1302,7 @@ namespace openssl { | |||||||
|           open? */ |           open? */ | ||||||
|       std::string read() { |       std::string read() { | ||||||
|         CRYPTOLOG("log"); |         CRYPTOLOG("log"); | ||||||
|         if (_bio<=0) throw tcp_closed_connection(); |         if (!_bio) throw tcp_closed_connection(); | ||||||
|         const int BUFF_SZ(1024); |         const int BUFF_SZ(1024); | ||||||
|         char buff[BUFF_SZ]; |         char buff[BUFF_SZ]; | ||||||
|         int x(BIO_read(_bio, buff, BUFF_SZ)); |         int x(BIO_read(_bio, buff, BUFF_SZ)); | ||||||
| @@ -1319,7 +1319,7 @@ namespace openssl { | |||||||
|  |  | ||||||
|       TCP& write(const std::string& s) { |       TCP& write(const std::string& s) { | ||||||
|         CRYPTOLOG("log"); |         CRYPTOLOG("log"); | ||||||
|         if (_bio<=0) throw tcp_closed_connection(); |         if (!_bio) throw tcp_closed_connection(); | ||||||
|         unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size())); |         unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size())); | ||||||
|         if (x<=0) |         if (x<=0) | ||||||
|           if (BIO_should_retry(_bio)) return write(s); |           if (BIO_should_retry(_bio)) return write(s); | ||||||
| @@ -1333,7 +1333,7 @@ namespace openssl { | |||||||
|        |        | ||||||
|       virtual TCP& close() { |       virtual TCP& close() { | ||||||
|         CRYPTOLOG("log"); |         CRYPTOLOG("log"); | ||||||
|         if (_bio>0) BIO_free_all(_bio); |         if (_bio) BIO_free_all(_bio); | ||||||
|         _bio = 0; |         _bio = 0; | ||||||
|         return *this; |         return *this; | ||||||
|       } |       } | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								src/pcsc.hxx
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								src/pcsc.hxx
									
									
									
									
									
								
							| @@ -490,13 +490,26 @@ namespace pcsc { | |||||||
|             - @c false: no exceptions, check your instance after each |             - @c false: no exceptions, check your instance after each | ||||||
|                         operation */ |                         operation */ | ||||||
|       Connection(Scope s=USER, bool exceptions=true): |       Connection(Scope s=USER, bool exceptions=true): | ||||||
|           _connectionlifetime(new ConnectionLifetime(s, exceptions)) { |           _connectionlifetime(connectionlifetime(s, exceptions)) { | ||||||
|  |         ++connectionlifetimecounter(); | ||||||
|  |         CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter()); | ||||||
|         check("establish smartcard context"); |         check("establish smartcard context"); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       Connection(const Connection& o)  { | ||||||
|  |         ++connectionlifetimecounter(); | ||||||
|  |         *this = o; | ||||||
|  |       } | ||||||
|  |  | ||||||
|       //! Closes the connection (releases the smartcard context) |       //! Closes the connection (releases the smartcard context) | ||||||
|       ~Connection() { |       ~Connection() { | ||||||
|         // connection is closed, when last _connectionlifetime is destructed |         // connection is closed, when _connectionlifetime is destructed | ||||||
|  |         if (--connectionlifetimecounter()==0) { | ||||||
|  |           CRYPTOLOG("Delete Connection"); | ||||||
|  |           delete connectionlifetime(); | ||||||
|  |           connectionlifetime()=0; | ||||||
|  |         } | ||||||
|  |         CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter()); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       //! Scans for available readers from a specified list of groups. |       //! Scans for available readers from a specified list of groups. | ||||||
| @@ -529,17 +542,15 @@ namespace pcsc { | |||||||
|       /*! First use scan() to get a list of readers, then open a |       /*! First use scan() to get a list of readers, then open a | ||||||
|           connection to the reader, then access it. */ |           connection to the reader, then access it. */ | ||||||
|       mrw::Shared<Reader> reader(const std::string& name) { |       mrw::Shared<Reader> reader(const std::string& name) { | ||||||
|         if (_readers.find(name)==_readers.end()) |         return _connectionlifetime->reader(name, this); | ||||||
|           _readers.insert(std::make_pair(name, new Reader(name, *this))); |  | ||||||
|         return _readers.find(name)->second; |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       //! Close connection of a named reader. |       // //! Close connection of a named reader. | ||||||
|       /*! If you access the same reader through raeder() later, the |       // /*! If you access the same reader through raeder() later, the | ||||||
|           connection will be reestablished. */ |       //     connection will be reestablished. */ | ||||||
|       void close(const std::string& s) { |       // void close(const std::string& s) { | ||||||
|          |          | ||||||
|       } |       // } | ||||||
|        |        | ||||||
|       //! Find all readers with a given ATR. |       //! Find all readers with a given ATR. | ||||||
|       /*! @param atr full or partial ATR to match to the reader's ATR |       /*! @param atr full or partial ATR to match to the reader's ATR | ||||||
| @@ -638,17 +649,21 @@ namespace pcsc { | |||||||
|           /*! @throw access_error if it is instanciated for exceptions and |           /*! @throw access_error if it is instanciated for exceptions and | ||||||
|               an error occured in the last command. */ |               an error occured in the last command. */ | ||||||
|           bool check(const std::string& context="") { |           bool check(const std::string& context="") { | ||||||
|             if (_exc&&!*this) |             if (_exc&&!*this) { | ||||||
|               if (context.size()) |               if (context.size()) { | ||||||
|                 if (_state==SCARD_W_WRONG_CHV) |                 if (_state==SCARD_W_WRONG_CHV) { | ||||||
|                   throw wrong_pin(context+": "+error()); |                   throw wrong_pin(context+": "+error()); | ||||||
|                 else |                 } else { | ||||||
|                   throw access_error(context+": "+error()); |                   throw access_error(context+": "+error()); | ||||||
|               else |                 } | ||||||
|                 if (_state==SCARD_W_WRONG_CHV) |               } else { | ||||||
|  |                 if (_state==SCARD_W_WRONG_CHV) { | ||||||
|                   throw wrong_pin(error()); |                   throw wrong_pin(error()); | ||||||
|                 else |                 } else { | ||||||
|                   throw access_error(error()); |                   throw access_error(error()); | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|             return *this; |             return *this; | ||||||
|           } |           } | ||||||
|  |  | ||||||
| @@ -906,23 +921,47 @@ namespace pcsc { | |||||||
|             return _exc; |             return _exc; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|  |           //! Get a reader, open a connection if not already open. | ||||||
|  |           /*! First use scan() to get a list of readers, then open a | ||||||
|  |               connection to the reader, then access it. */ | ||||||
|  |           mrw::Shared<Reader> reader(const std::string& name, Connection* c) { | ||||||
|  |             CRYPTOLOG("get reader: "<<name<<" from "<<(void*)&_readers); | ||||||
|  |             if (_readers.find(name)==_readers.end()) | ||||||
|  |               _readers.insert(std::make_pair(name, new Reader(name, *c))); | ||||||
|  |             return _readers.find(name)->second; | ||||||
|  |           } | ||||||
|  |  | ||||||
|         private: |         private: | ||||||
|  |  | ||||||
|           bool _exc; |           bool _exc; | ||||||
|           SCARDCONTEXT _id; |           SCARDCONTEXT _id; | ||||||
|           long _state; |           long _state; | ||||||
|       }; |  | ||||||
|        |        | ||||||
|  |           //! Readers are closed when the last shared object is destructed | ||||||
|       //! Readers are closed when the last shared object is destructed |           std::map<std::string, mrw::Shared<Reader> > _readers; | ||||||
|       std::map<std::string, mrw::Shared<Reader> > _readers; |       }; | ||||||
|  |  | ||||||
|       //! Connection is closed when the last shared object is destructed |       //! Connection is closed when the last shared object is destructed | ||||||
|       /*! Handling the connection lifetime in a separate shared object |       /*! Handling the connection lifetime in a separate shared object | ||||||
|           allows to copy connections and still make sure, that the |           allows to copy connections and still make sure, that the | ||||||
|           lifetime of the connection is as long as all copied opbjects |           lifetime of the connection is as long as all copied opbjects | ||||||
|           live. */ |           live. */ | ||||||
|       mrw::Shared<ConnectionLifetime> _connectionlifetime; |       static ConnectionLifetime*& | ||||||
|  |           connectionlifetime(Scope s=USER, bool exc=true) { | ||||||
|  |         static ConnectionLifetime* instance(0); | ||||||
|  |         if (instance==0) { | ||||||
|  |           CRYPTOLOG("New Connection"); | ||||||
|  |           instance = new ConnectionLifetime(s, exc); | ||||||
|  |         } | ||||||
|  |         return instance; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static int& connectionlifetimecounter() { | ||||||
|  |         static int instance(0); | ||||||
|  |         return instance; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ConnectionLifetime* _connectionlifetime; | ||||||
|  |  | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user