[gnutls-dev] c++ interface to gnutls.h

Rupert Kittinger-Sereinig rks at mur.at
Thu Jun 1 23:22:41 CEST 2006


Hi Nikos,

I have thought a little about decomposing the session class. From the 
code I have looked at, all the state information is supposed to be 
stored inside the gnutls_session_t. so it would be quite easy to build a 
derived class that just acts as a wrapper that adds some more functions.

e.g. like this:

class minimal_session {

// maybe this class should do nothing but manage the gnutls_session_t
// object

public:

	minimal_session(gnutls_connection_end_t t) {
		//
		//   I would not use RETWRAP functions here since the
        		//   constructor does not return anything
		//
		int ret = gnutls_init(&s_, t);
		if (ret != 0) throw(exception(ret));
         }

	virtual ~minimal_session() {
		gnutls_deinit(s_);
	}
		
protected:
	//
	//   all derived classes shall use the gnutls_session_t from
	//   an instance of minimal session
	// 	
	minimal_session() : s_(0) {}
	//
	// adding this function will prevent derived classes from
	// messing with the pointer.
         //
	const gnutls_session& get_session() { return s; }

private:
	//
	//   disable copying by declaring, but not defining copy
         //   constructor and assignement operator
	//
	minimal_session(const minimal session &s);

	minimal session& operator=(const minimal session &s);	
	
	//
	// adding a trailing underscore to member variables is a
	// nice convention used by a lot of people nowadays
	//	
	gnutls_session_t s_;
};

//
//  this class provides the configuration functionality
//

class config_session : public minimal session {

public:
	config_session(const session& other) : s_(other.get_session()) 		{}

	// default destructor is fine

	// copy ctor and assignement op are disabled because they are 			// 
private in the base class

	size_t get_max_size () const;

	void set_max_size(size_t size);

	...

private:
	const gnutls_session_t s_;		
};

//
//  this class provides the configuration functionality
//

class io_session : public minimal session {

public:
	// same as above
	io_session(const session& other) : s_(other.get_session()){}

	ssize_t record_recv (void * data, size_t sizeofdata);

	ssize_t record_send (const void * data, size_t sizeofdata);

	...

private:
	 const gnutls_session_t s_;
};

Now if we move configuration, data transfer, etc in separarte functions, 
we can create the right "view" of the class at the function call border:

void configure_session(config_session &s) {
	s.set_max_size(4711);
         ...
}

void send_something(io_session &s) {
	std::string msg("hello world\n");
	s.record_send(msg.c_str(), msg.size());

	...
}

These functions may be called like this:

int main() {
	minimal_session s(GNUTLS_CLIENT);

	// create a temporary for the function
	configure_session(config_session(s));

	send_something(io_session(s));

...
}


About coding in general: I do not have too much time either, but I think 
I will be able to do at least some detailed code reviewing.

greetings,
Rupert

PS: the CC should work now, I have updated my subscription data.

Nikos Mavrogiannopoulos schrieb:
> On Wed 31 May 2006 21:39, Rupert Kittinger-Sereinig wrote:
> 
>> I have not done a detailed review, but here are some points I
>> noticed:
> 
> Hello Rupert, 
>  thanks for the comments. I've already addressed some of them. (see 
> below)
> 
>> - exceptions for error handling: will all error conditions throw
>> exceptions?
> 
> Yes except for non fatal errors. The functions that only throw fatal
> exceptions now have a void return type.
> 
>> - I would like to be able to extract the error code from the
>> exception, not just a message string.
> Indeed. Updated.
> 
>> - I recommend removing all throw() specifications except where
>> required by the standard (i.e. exception::what()). See e.g. the boost
>> rationale:
>> http://www.boost.org/more/lib_guide.htm#Exception-specification
>> - All those get_ functions should get a const attribute.
> done.
> 
>> - most of the classes will need special treatment for copy and
>> assignement.
> 
> will address at a later time.
> 
>> - The session class looks somewhat bloated to me. How about providing
>> a hierarchy of classes that present different subsets of the
>> functionality?
> 
> Indeed it could be cleaner. Any proposals? 
> 
>> - consistency: the c interface uses a mixture of gnutls_datum, char*,
>> unsigned char*, void*, paired with unsigned int, size_t. It would be
>> great if the c++ Interface would just stick to one variant, like
>> std::vector<unsigned char>.
> 
> Hmmm that's tricky to wrap in most of the cases, but it would provide a 
> cleaner api, that's true. If you have any good suggestions on that 
> they're welcome.
> 
>> - I think there a session cache should be implemented as an object.
>> so it would be nice to provide a base class that provides member
>> functions equivalent to the gnutls_db_func types and handles the
>> installation of forwarding functions.
> 
> Yes this was my original idea. Now it's implemented. 
> 
> In general i've quite limited time for that so if you or anyone else is 
> interested in that and more in hurry than me, I've put my current 
> sources at:
> http://members.hellug.gr/nmav/misc/gnutlsxx.h
> http://members.hellug.gr/nmav/misc/gnutlsxx.cpp
> 
> 
>> cheers,
>> Rupert
>>
>>> -------------------------------------------------------------------
>>> -----
>>>
>>> #ifndef GNUTLSXX_H
>>> # define GNUTLSXX_H
>>>
>>> #include <exception>
>>> #include <vector>
>>> #include <gnutls.h>
>>>
>>> namespace gnutls {
>>>
>>> class exception: public std::exception
>>> {
>>>     public:
>>>         exception( int x);
>>>         const char* what() const throw();
>>>     protected:
>>>         int retcode;
>>> };
>>>
>>>
>>>
>>> class dh_params
>>> {
>>>     public:
>>>         dh_params();
>>>         ~dh_params();
>>>         void import_raw( const gnutls_datum_t & prime,
>>>                      const gnutls_datum_t & generator);
>>>         void import_pkcs3( const gnutls_datum_t & pkcs3_params,
>>>                            gnutls_x509_crt_fmt_t format);
>>>         void generate( unsigned int bits);
>>>
>>>         void export_pkcs3( gnutls_x509_crt_fmt_t format, unsigned
>>> char *params_data, size_t * params_data_size); void export_raw(
>>> gnutls_datum_t& prime, gnutls_datum_t &generator);
>>>
>>>         gnutls_dh_params_t get_params_t() const;
>>>         dh_params & operator=(const dh_params& src);
>>>     protected:
>>>         gnutls_dh_params_t params;
>>> };
>>>
>>>
>>> class rsa_params
>>> {
>>>     public:
>>>         rsa_params();
>>>         ~rsa_params();
>>>         void import_raw( const gnutls_datum_t & m,
>>>                      const gnutls_datum_t & e,
>>>                      const gnutls_datum_t & d,
>>>                      const gnutls_datum_t & p,
>>>                      const gnutls_datum_t & q,
>>>                      const gnutls_datum_t & u);
>>>         void import_pkcs1( const gnutls_datum_t & pkcs1_params,
>>>                            gnutls_x509_crt_fmt_t format);
>>>         void generate( unsigned int bits);
>>>
>>>         void export_pkcs1( gnutls_x509_crt_fmt_t format, unsigned
>>> char *params_data, size_t * params_data_size); void export_raw( 
>>> gnutls_datum_t & m, gnutls_datum_t & e, gnutls_datum_t & d,
>>> gnutls_datum_t & p, gnutls_datum_t & q, gnutls_datum_t & u);
>>> gnutls_rsa_params_t get_params_t() const;
>>>         rsa_params & operator=(const rsa_params& src);
>>>
>>>     protected:
>>>         gnutls_rsa_params_t params;
>>> };
>>>
>>> enum priority_flag { ALL_CIPHERS, EXPORT_CIPHERS };
>>>
>>> class session
>>> {
>>>     protected:
>>>         gnutls_session_t s;
>>>
>>>     public:
>>>         session( gnutls_connection_end_t);
>>>         virtual ~session();
>>>
>>>         int bye( gnutls_close_request_t how);
>>>         int handshake ();
>>>
>>>         gnutls_alert_description_t get_alert() throw();
>>>
>>>         int send_alert ( gnutls_alert_level_t level,
>>>                          gnutls_alert_description_t desc);
>>>         int send_appropriate_alert (int err);
>>>
>>>         gnutls_cipher_algorithm_t get_cipher() throw();
>>>         gnutls_kx_algorithm_t get_kx () throw();
>>>         gnutls_mac_algorithm_t get_mac () throw();
>>>         gnutls_compression_method_t get_compression () throw();
>>>         gnutls_certificate_type_t get_certificate_type() throw();
>>>
>>>         // for the handshake
>>>         void set_private_extensions ( bool allow) throw();
>>>
>>>         gnutls_handshake_description_t get_handshake_last_out()
>>> throw(); gnutls_handshake_description_t get_handshake_last_in()
>>> throw();
>>>
>>>         ssize_t send (const void *data, size_t sizeofdata);
>>>         ssize_t recv (void *data, size_t sizeofdata);
>>>
>>>         bool get_record_direction() throw();
>>>
>>>         // maximum packet size
>>>         size_t get_max_size() throw();
>>>         void set_max_size(size_t size);
>>>
>>>         size_t check_pending() throw();
>>>
>>>         void prf (size_t label_size, const char *label,
>>>                         int server_random_first,
>>>                         size_t extra_size, const char *extra,
>>>                         size_t outsize, char *out);
>>>
>>>         void prf_raw ( size_t label_size, const char *label,
>>>                       size_t seed_size, const char *seed,
>>>                       size_t outsize, char *out);
>>>
>>>         void set_cipher_priority (const int *list);
>>>         void set_mac_priority (const int *list);
>>>         void set_compression_priority (const int *list);
>>>         void set_kx_priority (const int *list);
>>>         void set_protocol_priority (const int *list);
>>>         void set_certificate_type_priority (const int *list);
>>>
>>> /* if you just want some defaults, use the following.
>>>  */
>>>         void set_default_priority (priority_flag flag);
>>>
>>>         gnutls_protocol_t get_protocol_version() throw();
>>>
>>>         // for resuming sessions
>>>         void set_data ( const void *session_data,
>>>                         size_t session_data_size);
>>>         void get_data (void *session_data,
>>>                        size_t * session_data_size);
>>>         void get_data(gnutls_session_t session,
>>>                         gnutls_datum_t & data);
>>>         void get_id ( void *session_id,
>>>                       size_t * session_id_size);
>>>
>>>         bool is_resumed () throw();
>>>
>>>         void set_max_handshake_packet_length ( size_t max) throw();
>>>
>>>         void clear_credentials() throw();
>>>         void set_credentials( class credentials & cred);
>>>
>>>         void set_transport_ptr( gnutls_transport_ptr_t ptr);
>>>         void set_transport_ptr( gnutls_transport_ptr_t recv_ptr,
>>> gnutls_transport_ptr_t send_ptr); gnutls_transport_ptr_t
>>> get_transport_ptr();
>>>         void get_transport_ptr(gnutls_transport_ptr_t * recv_ptr,
>>>                                gnutls_transport_ptr_t * send_ptr);
>>>
>>>         void set_transport_lowat (size_t num);
>>>         void set_transport_push_function( gnutls_push_func
>>> push_func); void set_transport_pull_function( gnutls_pull_func
>>> pull_func);
>>>
>>>         void set_user_ptr( void* ptr);
>>>         void *get_user_ptr();
>>>
>>>         void send_openpgp_key( gnutls_openpgp_key_status_t status);
>>>
>>>         gnutls_credentials_type_t get_auth_type();
>>>         gnutls_credentials_type_t get_server_auth_type();
>>>         gnutls_credentials_type_t get_client_auth_type();
>>>
>>>         // informational stuff
>>>         void set_dh_prime_bits( unsigned int bits);
>>>         unsigned int get_dh_secret_bits();
>>>         unsigned int get_dh_peers_public_bits();
>>>         unsigned int get_dh_prime_bits();
>>>         void get_dh_group( gnutls_datum_t & gen, gnutls_datum_t &
>>> prime); void get_dh_pubkey( gnutls_datum_t & raw_key);
>>>         void get_rsa_export_pubkey( gnutls_datum& exponent,
>>> gnutls_datum& modulus); unsigned int get_rsa_export_modulus_bits();
>>>
>>>         const gnutls_datum* get_our_certificate();
>>>         bool get_peers_certificate(std::vector<gnutls_datum_t>
>>> &out_certs); bool get_peers_certificate(const gnutls_datum_t**
>>> certs, unsigned int *certs_size);
>>>
>>>         time_t get_peers_certificate_activation_time();
>>>         time_t get_peers_certificate_expiration_time();
>>>         void verify_peers_certificate( unsigned int& status);
>>>
>>>
>>> };
>>>
>>> class server_session: public session
>>> {
>>>
>>>     void set_db_cache_expiration (unsigned int seconds) throw();
>>>     void db_remove ();
>>>     void set_db_retrieve_function ( gnutls_db_retr_func retr_func);
>>>     void set_db_remove_function ( gnutls_db_remove_func rem_func);
>>>     void set_db_store_function ( gnutls_db_store_func store_func);
>>>     void set_db_ptr ( void *ptr);
>>>     void *get_db_ptr ();
>>>
>>>         // returns true if session is expired
>>>     bool db_check_entry ( gnutls_datum_t &session_entry);
>>>
>>>     // server side only
>>>     const char *get_srp_username();
>>>     const char *get_psk_username();
>>>
>>>     void get_server_name (void *data, size_t * data_length,
>>>                           unsigned int *type, unsigned int indx);
>>>
>>>     int rehandshake();
>>>     void set_certificate_request( gnutls_certificate_request_t);
>>>
>>> };
>>>
>>> class client_session: public session
>>> {
>>>     void set_server_name (gnutls_server_name_type_t type,
>>>                           const void *name, size_t name_length);
>>>
>>>     bool client_session::get_request_status();
>>> };
>>>
>>>
>>> class credentials
>>> {
>>>     public:
>>>         credentials(gnutls_credentials_type_t t) : type(t) { }
>>>         virtual ~credentials() { }
>>>         gnutls_credentials_type_t get_type();
>>>     protected:
>>>         friend class session;
>>>         virtual void* ptr();
>>>         gnutls_credentials_type_t type;
>>> };
>>>
>>> class certificate_credentials: public credentials
>>> {
>>>     public:
>>>         ~certificate_credentials();
>>>         certificate_credentials();
>>>
>>>         void free_keys ();
>>>         void free_cas ();
>>>         void free_ca_names ();
>>>         void free_crls ();
>>>
>>>         void set_dh_params ( const dh_params &params);
>>>         void set_rsa_export_params ( const rsa_params& params);
>>>         void set_verify_flags ( unsigned int flags);
>>>         void set_verify_limits ( unsigned int max_bits, unsigned
>>> int max_depth);
>>>
>>>         void set_x509_trust_file(const char *cafile,
>>> gnutls_x509_crt_fmt_t type); void set_x509_trust(const
>>> gnutls_datum_t & CA, gnutls_x509_crt_fmt_t type); // FIXME: use
>>> classes instead of gnutls_x509_crt_t void set_x509_trust (
>>> gnutls_x509_crt_t * ca_list, int ca_list_size);
>>>
>>>         void set_x509_crl_file( const char *crlfile,
>>> gnutls_x509_crt_fmt_t type); void set_x509_crl(const gnutls_datum_t
>>> & CRL, gnutls_x509_crt_fmt_t type); void set_x509_crl (
>>> gnutls_x509_crl_t * crl_list, int crl_list_size);
>>>
>>>         void set_x509_key_file(const char *certfile, const char
>>> *KEYFILE, gnutls_x509_crt_fmt_t type); void set_x509_key(const
>>> gnutls_datum_t & CERT, const gnutls_datum_t & KEY,
>>> gnutls_x509_crt_fmt_t type); // FIXME: use classes
>>>         void set_x509_key ( gnutls_x509_crt_t * cert_list, int
>>> cert_list_size, gnutls_x509_privkey_t key);
>>>
>>>
>>>         void set_simple_pkcs12_file( const char *pkcs12file,
>>>                  gnutls_x509_crt_fmt_t type, const char *password);
>>>
>>>     protected:
>>>         void* ptr();
>>>         gnutls_certificate_credentials_t cred;
>>> };
>>>
>>> class certificate_server_credentials: public
>>> certificate_credentials {
>>>     certificate_server_credentials() { }
>>>     public:
>>>         void set_retrieve_function(
>>> gnutls_certificate_server_retrieve_function* func) throw(); void
>>> set_params_function( gnutls_params_function* func) throw(); };
>>>
>>> class certificate_client_credentials: public
>>> certificate_credentials {
>>>     public:
>>>         certificate_client_credentials() { }
>>>         void set_retrieve_function(
>>> gnutls_certificate_client_retrieve_function* func) throw(); };
>>>
>>>
>>>
>>>
>>> class anon_server_credentials: public credentials
>>> {
>>>     public:
>>>         anon_server_credentials();
>>>         ~anon_server_credentials();
>>>         void set_dh_params ( const dh_params &params);
>>>         void set_params_function ( gnutls_params_function * func)
>>> throw(); protected:
>>>         gnutls_anon_server_credentials_t cred;
>>> };
>>>
>>> class anon_client_credentials: public credentials
>>> {
>>>     public:
>>>         anon_client_credentials();
>>>         ~anon_client_credentials();
>>>     protected:
>>>         gnutls_anon_client_credentials_t cred;
>>> };
>>>
>>>
>>> class srp_server_credentials: public credentials
>>> {
>>>     public:
>>>         srp_server_credentials();
>>>         ~srp_server_credentials();
>>>         void set_credentials_file (const char *password_file, const
>>> char *password_conf_file); void set_credentials_function(
>>> gnutls_srp_server_credentials_function *func); protected:
>>>         void* ptr();
>>>         gnutls_srp_server_credentials_t cred;
>>> };
>>>
>>> class srp_client_credentials: public credentials
>>> {
>>>     public:
>>>         srp_client_credentials();
>>>         ~srp_client_credentials();
>>>         void set_credentials (const char *username, const char
>>> *password); void set_credentials_function(
>>> gnutls_srp_client_credentials_function* func); protected:
>>>         void* ptr();
>>>         gnutls_srp_client_credentials_t cred;
>>> };
>>>
>>>
>>> class psk_server_credentials: public credentials
>>> {
>>>     public:
>>>         psk_server_credentials();
>>>         ~psk_server_credentials();
>>>         void set_credentials_file(const char* password_file);
>>>         void set_credentials_function(
>>> gnutls_psk_server_credentials_function* func); void set_dh_params (
>>> const dh_params &params);
>>>         void set_params_function (gnutls_params_function * func)
>>> throw(); protected:
>>>         void* ptr();
>>>         gnutls_psk_server_credentials_t cred;
>>> };
>>>
>>> class psk_client_credentials: public credentials
>>> {
>>>     public:
>>>         psk_client_credentials();
>>>         ~psk_client_credentials();
>>>         void set_credentials (const char *username, const
>>> gnutls_datum_t& key, gnutls_psk_key_flags flags); void
>>> set_credentials_function( gnutls_psk_client_credentials_function*
>>> func); protected:
>>>         void* ptr();
>>>         gnutls_psk_client_credentials_t cred;
>>> };
>>>
>>>
>>> }; /* namespace */
>>>
>>> #endif                          /* GNUTLSXX_H */
>>>
>>>
>>> -------------------------------------------------------------------
>>> -----
>>>
>>> _______________________________________________
>>> Gnutls-dev mailing list
>>> Gnutls-dev at gnupg.org
>>> http://lists.gnupg.org/mailman/listinfo/gnutls-dev


-- 
Rupert Kittinger-Sereinig <rks at mur.at>
Krenngasse 32
A-8010 Graz
Austria




More information about the Gnutls-dev mailing list