From 64731e1dc953a43430351ed3cccdf59da4b1bf43 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 15 Jun 2011 18:58:34 +0000 Subject: [PATCH] +ecore_con_ssl_server_upgrade +ecore_con_ssl_client_upgrade +ECORE_CON_EVENT_SERVER_UPGRADE +ECORE_CON_EVENT_CLIENT_UPGRADE new functions for upgrading an existing plaintext connection to SSL/TLS, as seen in STARTTLS and my nightmares SVN revision: 60359 --- legacy/ecore/ChangeLog | 6 + legacy/ecore/src/lib/ecore_con/Ecore_Con.h | 36 +++++ legacy/ecore/src/lib/ecore_con/ecore_con.c | 14 +- .../ecore/src/lib/ecore_con/ecore_con_ares.c | 2 +- .../src/lib/ecore_con/ecore_con_private.h | 5 +- .../ecore/src/lib/ecore_con/ecore_con_ssl.c | 130 +++++++++++++++--- 6 files changed, 164 insertions(+), 29 deletions(-) diff --git a/legacy/ecore/ChangeLog b/legacy/ecore/ChangeLog index 12008fc80b..5e2fb4760e 100644 --- a/legacy/ecore/ChangeLog +++ b/legacy/ecore/ChangeLog @@ -214,3 +214,9 @@ 2011-06-09 Cedric Bail * Add ecore_pipe_wait (should only called from outside of the main loop). + +2011-06-15 Mike Blumenkrantz + + * Add ecore_con_ssl_client/server_upgrade to begin asynchronously upgrading an + existing connection to SSL/TLS, emitting ECORE_CON_CLIENT/SERVER_UPGRADE event + upon completion. diff --git a/legacy/ecore/src/lib/ecore_con/Ecore_Con.h b/legacy/ecore/src/lib/ecore_con/Ecore_Con.h index 4d9460f187..25a945c39f 100644 --- a/legacy/ecore/src/lib/ecore_con/Ecore_Con.h +++ b/legacy/ecore/src/lib/ecore_con/Ecore_Con.h @@ -145,6 +145,12 @@ typedef struct _Ecore_Con_Url Ecore_Con_Url; */ typedef struct _Ecore_Con_Event_Client_Add Ecore_Con_Event_Client_Add; +/** + * @typedef Ecore_Con_Event_Client_Upgrade + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Client_Upgrade Ecore_Con_Event_Client_Upgrade; + /** * @typedef Ecore_Con_Event_Client_Del * Used as the @p data param for the corresponding event @@ -163,6 +169,12 @@ typedef struct _Ecore_Con_Event_Client_Error Ecore_Con_Event_Client_Error; */ typedef struct _Ecore_Con_Event_Server_Add Ecore_Con_Event_Server_Add; +/** + * @typedef Ecore_Con_Event_Server_Upgrade + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Server_Upgrade Ecore_Con_Event_Server_Upgrade; + /** * @typedef Ecore_Con_Event_Server_Del * Used as the @p data param for the corresponding event @@ -214,6 +226,15 @@ struct _Ecore_Con_Event_Client_Add Ecore_Con_Client *client; /** the client that connected */ }; +/** + * @struct _Ecore_Con_Event_Client_Upgrade + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_UPGRADE event + */ +struct _Ecore_Con_Event_Client_Upgrade +{ + Ecore_Con_Client *client; /** the client that completed handshake */ +}; + /** * @struct _Ecore_Con_Event_Client_Del * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_DEL event @@ -242,6 +263,15 @@ struct _Ecore_Con_Event_Server_Add Ecore_Con_Server *server; /** the server that was connected to */ }; +/** + * @struct _Ecore_Con_Event_Server_Upgrade + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_UPGRADE event + */ +struct _Ecore_Con_Event_Server_Upgrade +{ + Ecore_Con_Server *server; /** the server that was connected to */ +}; + /** * @struct _Ecore_Con_Event_Server_Del * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_DEL event @@ -329,12 +359,16 @@ EAPI extern int ECORE_CON_EVENT_CLIENT_ADD; EAPI extern int ECORE_CON_EVENT_CLIENT_DEL; /** A client experienced an error */ EAPI extern int ECORE_CON_EVENT_CLIENT_ERROR; +/** A client connection has been upgraded to SSL */ +EAPI extern int ECORE_CON_EVENT_CLIENT_UPGRADE; /** A server was created */ EAPI extern int ECORE_CON_EVENT_SERVER_ADD; /** A server connection was lost */ EAPI extern int ECORE_CON_EVENT_SERVER_DEL; /** A server experienced an error */ EAPI extern int ECORE_CON_EVENT_SERVER_ERROR; +/** A server connection has been upgraded to SSL */ +EAPI extern int ECORE_CON_EVENT_SERVER_UPGRADE; /** A client connected to the server has sent data */ EAPI extern int ECORE_CON_EVENT_CLIENT_DATA; /** A server connection object has data */ @@ -427,6 +461,8 @@ EAPI Eina_Bool ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, c EAPI Eina_Bool ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const char *crl_file); EAPI Eina_Bool ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *ca_file); EAPI void ecore_con_ssl_server_verify(Ecore_Con_Server *svr); +EAPI Eina_Bool ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type); +EAPI Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type); /** * @} diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con.c b/legacy/ecore/src/lib/ecore_con/ecore_con.c index 6450781c06..4074ea46e8 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con.c +++ b/legacy/ecore/src/lib/ecore_con/ecore_con.c @@ -1178,13 +1178,15 @@ ecore_con_event_server_add(Ecore_Con_Server *svr) { /* we got our server! */ Ecore_Con_Event_Server_Add *e; + int ev = ECORE_CON_EVENT_SERVER_ADD; e = calloc(1, sizeof(Ecore_Con_Event_Server_Add)); EINA_SAFETY_ON_NULL_RETURN(e); svr->event_count++; e->server = svr; - ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e, + if (svr->upgrade) ev = ECORE_CON_EVENT_SERVER_UPGRADE; + ecore_event_add(ev, e, _ecore_con_event_server_add_free, NULL); } @@ -1234,6 +1236,7 @@ void ecore_con_event_client_add(Ecore_Con_Client *cl) { Ecore_Con_Event_Client_Add *e; + int ev = ECORE_CON_EVENT_CLIENT_ADD; e = calloc(1, sizeof(Ecore_Con_Event_Client_Add)); EINA_SAFETY_ON_NULL_RETURN(e); @@ -1242,7 +1245,8 @@ ecore_con_event_client_add(Ecore_Con_Client *cl) cl->host_server->event_count++; _ecore_con_cl_timer_update(cl); e->client = cl; - ecore_event_add(ECORE_CON_EVENT_CLIENT_ADD, e, + if (cl->upgrade) ev = ECORE_CON_EVENT_CLIENT_UPGRADE; + ecore_event_add(ev, e, (Ecore_End_Cb)_ecore_con_event_client_add_free, cl->host_server); } @@ -2018,7 +2022,7 @@ _ecore_con_svr_tcp_handler(void *data, ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); - if (svr->type & ECORE_CON_SSL) + if ((!svr->upgrade) && (svr->type & ECORE_CON_SSL)) { cl->handshaking = EINA_TRUE; cl->ssl_state = ECORE_CON_SSL_STATE_INIT; @@ -2284,7 +2288,7 @@ _ecore_con_svr_cl_read(Ecore_Con_Client *cl) _ecore_con_cl_timer_update(cl); } - if (!(cl->host_server->type & ECORE_CON_SSL)) + if (!(cl->host_server->type & ECORE_CON_SSL) || (!cl->upgrade)) { num = read(cl->fd, buf, sizeof(buf)); /* 0 is not a valid return value for a tcp socket */ @@ -2445,7 +2449,7 @@ _ecore_con_client_flush(Ecore_Con_Client *cl) { num = cl->buf_size - cl->buf_offset; if (num <= 0) return; - if (!(cl->host_server->type & ECORE_CON_SSL)) + if (!(cl->host_server->type & ECORE_CON_SSL) || (!cl->upgrade)) count = write(cl->fd, cl->buf + cl->buf_offset, num); else count = ecore_con_ssl_client_write(cl, cl->buf + cl->buf_offset, num); diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con_ares.c b/legacy/ecore/src/lib/ecore_con/ecore_con_ares.c index f66ac096d6..95369d6ec9 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con_ares.c +++ b/legacy/ecore/src/lib/ecore_con/ecore_con_ares.c @@ -314,7 +314,7 @@ void ecore_con_info_data_clear(void *info) { Ecore_Con_CAres *cares = info; - cares->data = NULL; + if (cares) cares->data = NULL; } static Eina_Bool diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con_private.h b/legacy/ecore/src/lib/ecore_con/ecore_con_private.h index f484b2db6a..0e8057c8be 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con_private.h +++ b/legacy/ecore/src/lib/ecore_con/ecore_con_private.h @@ -106,8 +106,9 @@ struct _Ecore_Con_Client SSL *ssl; int ssl_err; #endif - Eina_Bool handshaking : 1; Ecore_Con_Ssl_State ssl_state; + Eina_Bool handshaking : 1; + Eina_Bool upgrade : 1; Eina_Bool dead : 1; Eina_Bool delete_me : 1; }; @@ -152,6 +153,8 @@ struct _Ecore_Con_Server Eina_Bool created : 1; /* EINA_TRUE if server is our listening server */ Eina_Bool connecting : 1; /* EINA_FALSE if just initialized or connected */ Eina_Bool handshaking : 1; /* EINA_TRUE if server is ssl handshaking */ + Eina_Bool upgrade : 1; + Eina_Bool ssl_prepared : 1; Eina_Bool use_cert : 1; /* EINA_TRUE if using certificate auth */ Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */ Eina_Bool verify : 1; /* EINA_TRUE if certificates will be verified */ diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c b/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c index 1b74999b85..a6cbe471e9 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c +++ b/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c @@ -21,6 +21,9 @@ #include #include +EAPI int ECORE_CON_EVENT_CLIENT_UPGRADE = 0; +EAPI int ECORE_CON_EVENT_SERVER_UPGRADE = 0; + static int _init_con_ssl_init_count = 0; #ifdef USE_GNUTLS @@ -157,29 +160,16 @@ static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (Ecore_Con static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (Ecore_Con_Server * svr, const char *key_file); static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_prepare) (Ecore_Con_Server * svr, int ssl_type); -static Ecore_Con_Ssl_Error - SSL_SUFFIX(_ecore_con_ssl_server_init) (Ecore_Con_Server * svr); -static Ecore_Con_Ssl_Error - SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (Ecore_Con_Server * - svr); -static int -SSL_SUFFIX(_ecore_con_ssl_server_read) (Ecore_Con_Server * svr, - unsigned char *buf, int size); -static int -SSL_SUFFIX(_ecore_con_ssl_server_write) (Ecore_Con_Server * - svr, - unsigned char *buf, int size); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_init) (Ecore_Con_Server * svr); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (Ecore_Con_Server *svr); +static int SSL_SUFFIX(_ecore_con_ssl_server_read) (Ecore_Con_Server *svr, unsigned char *buf, int size); +static int SSL_SUFFIX(_ecore_con_ssl_server_write) (Ecore_Con_Server *svr, unsigned char *buf, int size); -static Ecore_Con_Ssl_Error - SSL_SUFFIX(_ecore_con_ssl_client_init) (Ecore_Con_Client * cl); -static Ecore_Con_Ssl_Error - SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (Ecore_Con_Client * - cl); -static int -SSL_SUFFIX(_ecore_con_ssl_client_read) (Ecore_Con_Client * cl, +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_init) (Ecore_Con_Client * cl); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (Ecore_Con_Client *cl); +static int SSL_SUFFIX(_ecore_con_ssl_client_read) (Ecore_Con_Client * cl, unsigned char *buf, int size); -static int -SSL_SUFFIX(_ecore_con_ssl_client_write) (Ecore_Con_Client * cl, +static int SSL_SUFFIX(_ecore_con_ssl_client_write) (Ecore_Con_Client * cl, unsigned char *buf, int size); /* @@ -190,7 +180,13 @@ Ecore_Con_Ssl_Error ecore_con_ssl_init(void) { if (!_init_con_ssl_init_count++) - SSL_SUFFIX(_ecore_con_ssl_init) (); + { + SSL_SUFFIX(_ecore_con_ssl_init) (); +#if _ECORE_CON_SSL_AVAILABLE != 0 + ECORE_CON_EVENT_CLIENT_UPGRADE = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_UPGRADE = ecore_event_type_new(); +#endif + } return _init_con_ssl_init_count; } @@ -409,6 +405,82 @@ ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, return SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (svr, crl_file); } +/** + * @brief Upgrade a connection to a specified level of encryption + * + * Use this function to begin an SSL handshake on a connection (STARTTLS or similar). + * Once the upgrade has been completed, an ECORE_CON_EVENT_SERVER_UPGRADE event will be emitted. + * The connection should be treated as disconnected until the next event. + * @param svr The server object + * @param ssl_type The SSL connection type (ONLY). + * @return EINA_FALSE if the connection cannot be upgraded, otherwise EINA_TRUE. + * @note This function is NEVER to be used on a server object created with ecore_con_server_add + * @warning Setting a wrong value for @p compl_type WILL mess up your program. + * @since 1.1 + */ + +EAPI Eina_Bool +ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type ssl_type) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return EINA_FALSE; + } +#if _ECORE_CON_SSL_AVAILABLE == 0 + return EINA_FALSE; +#endif + + if (!svr->ssl_prepared) + { + if (ecore_con_ssl_server_prepare(svr, ssl_type)) + return EINA_FALSE; + } + svr->type |= ssl_type; + svr->upgrade = EINA_TRUE; + svr->handshaking = EINA_TRUE; + svr->ssl_state = ECORE_CON_SSL_STATE_INIT; + return !SSL_SUFFIX(_ecore_con_ssl_server_init) (svr); +} + +/** + * @brief Upgrade a connection to a specified level of encryption + * + * Use this function to begin an SSL handshake on a connection (STARTTLS or similar). + * Once the upgrade has been completed, an ECORE_CON_EVENT_CLIENT_UPGRADE event will be emitted. + * The connection should be treated as disconnected until the next event. + * @param cl The client object + * @param compl_type The SSL connection type (ONLY). + * @return EINA_FALSE if the connection cannot be upgraded, otherwise EINA_TRUE. + * @warning Setting a wrong value for @p compl_type WILL mess up your program. + * @since 1.1 + */ + +EAPI Eina_Bool +ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type ssl_type) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__); + return EINA_FALSE; + } +#if _ECORE_CON_SSL_AVAILABLE == 0 + return EINA_FALSE; +#endif + + if (!cl->host_server->ssl_prepared) + { + if (ecore_con_ssl_server_prepare(cl->host_server, ssl_type)) + return EINA_FALSE; + } + cl->host_server->type |= ssl_type; + cl->upgrade = EINA_TRUE; + cl->host_server->upgrade = EINA_TRUE; + cl->handshaking = EINA_TRUE; + cl->ssl_state = ECORE_CON_SSL_STATE_INIT; + return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl); +} + /** * @} */ @@ -490,6 +562,7 @@ _ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr, SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_client_credentials(&svr->anoncred_c)); } + svr->ssl_prepared = EINA_TRUE; return ECORE_CON_SSL_ERROR_NONE; error: @@ -498,6 +571,7 @@ error: return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; } + static Ecore_Con_Ssl_Error _ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr) { @@ -1538,6 +1612,12 @@ _ecore_con_ssl_server_prepare_none(Ecore_Con_Server *svr __UNUSED__, return ECORE_CON_SSL_ERROR_NONE; } +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_upgrade_none(Ecore_Con_Server *svr __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + static Ecore_Con_Ssl_Error _ecore_con_ssl_server_init_none(Ecore_Con_Server *svr __UNUSED__) { @@ -1594,6 +1674,12 @@ _ecore_con_ssl_server_write_none(Ecore_Con_Server *svr __UNUSED__, return -1; } +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_upgrade_none(Ecore_Con_Client *cl __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + static Ecore_Con_Ssl_Error _ecore_con_ssl_client_init_none(Ecore_Con_Client *cl __UNUSED__) {