Loading lib/ssluse.c +186 −0 Original line number Diff line number Diff line Loading @@ -278,10 +278,43 @@ void Curl_SSL_init(void) #endif } /* * This function is called when an SSL connection is closed. */ void Curl_SSL_Close(struct connectdata *conn) { if (conn->ssl.use) { /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its error queue removed. Since error queue data structures are allocated automatically for new threads, they must be freed when threads are terminated in oder to avoid memory leaks. */ ERR_remove_state(0); if(conn->ssl.handle) { (void)SSL_shutdown(conn->ssl.handle); SSL_set_connect_state(conn->ssl.handle); SSL_free (conn->ssl.handle); conn->ssl.handle = NULL; } if(conn->ssl.ctx) { SSL_CTX_free (conn->ssl.ctx); conn->ssl.ctx = NULL; } conn->ssl.use = FALSE; /* get back to ordinary socket usage */ } } /* Global cleanup */ void Curl_SSL_cleanup(void) { #ifdef USE_SSLEAY if(init_ssl) { /* only cleanup if we did a previous init */ Loading @@ -295,6 +328,140 @@ void Curl_SSL_cleanup(void) #endif } /* * This sets up a session cache to the specified size. */ CURLcode Curl_SSL_InitSessions(struct UrlData *data, long amount) { struct curl_ssl_session *session; if(data->ssl.session) /* this is just a precaution to prevent multiple inits */ return CURLE_OK; session = (struct curl_ssl_session *) malloc(amount * sizeof(struct curl_ssl_session)); if(!session) return CURLE_OUT_OF_MEMORY; /* "blank out" the newly allocated memory */ memset(session, 0, amount * sizeof(struct curl_ssl_session)); /* store the info in the SSL section */ data->ssl.numsessions = amount; data->ssl.session = session; data->ssl.sessionage = 1; /* this is brand new */ return CURLE_OK; } /* * Check if there's a session ID for the given connection in the cache, * and if there's one suitable, it is returned. */ static int Get_SSL_Session(struct connectdata *conn, SSL_SESSION **ssl_sessionid) { struct curl_ssl_session *check; struct UrlData *data = conn->data; long i; for(i=0; i< data->ssl.numsessions; i++) { check = &data->ssl.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; if(strequal(conn->name, check->name)) { /* yes, we have a session ID! */ data->ssl.sessionage++; /* increase general age */ check->age = data->ssl.sessionage; /* set this as used in this age */ *ssl_sessionid = check->sessionid; return FALSE; } } *ssl_sessionid = (SSL_SESSION *)NULL; return TRUE; } /* * Kill a single session ID entry in the cache. */ static int Kill_Single_Session(struct curl_ssl_session *session) { if(session->sessionid) { /* defensive check */ /* free the ID */ SSL_SESSION_free(session->sessionid); session->sessionid=NULL; session->age = 0; /* fresh */ free(session->name); session->name = NULL; /* no name */ return 0; /* ok */ } else return 1; } /* * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ int Curl_SSL_Close_All(struct UrlData *data) { int i; for(i=0; i< data->ssl.numsessions; i++) /* the single-killer function handles empty table slots */ Kill_Single_Session(&data->ssl.session[i]); /* free the cache data */ free(data->ssl.session); return 0; } /* * Extract the session id and store it in the session cache. */ static int Store_SSL_Session(struct connectdata *conn) { SSL_SESSION *ssl_sessionid; struct curl_ssl_session *store; int i; struct UrlData *data=conn->data; /* the mother of all structs */ int oldest_age=data->ssl.session[0].age; /* zero if unused */ /* ask OpenSSL, say please */ ssl_sessionid = SSL_get1_session(conn->ssl.handle); /* SSL_get1_session() will increment the reference count and the session will stay in memory until explicitly freed with SSL_SESSION_free(3), regardless of its state. */ /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* find an empty slot for us, or find the oldest */ for(i=0; (i<data->ssl.numsessions) && data->ssl.session[i].sessionid; i++) { if(data->ssl.session[i].age < oldest_age) { oldest_age = data->ssl.session[i].age; store = &data->ssl.session[i]; } } if(i == data->ssl.numsessions) /* cache is full, we must "kill" the oldest entry! */ Kill_Single_Session(store); else store = &data->ssl.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->age = data->ssl.sessionage; /* set current age */ store->name = strdup(conn->name); /* clone host name */ return 0; } /* ====================================================== */ CURLcode Loading @@ -307,6 +474,7 @@ Curl_SSLConnect(struct connectdata *conn) int err; char * str; SSL_METHOD *req_method; SSL_SESSION *ssl_sessionid=NULL; /* mark this is being ssl enabled from here on out. */ conn->ssl.use = TRUE; Loading Loading @@ -362,6 +530,17 @@ Curl_SSLConnect(struct connectdata *conn) conn->ssl.server_cert = 0x0; if(!conn->bits.reuse) { /* We're not re-using a connection, check if there's a cached ID we can/should use here! */ if(!Get_SSL_Session(conn, &ssl_sessionid)) { /* we got a session id, use it! */ SSL_set_session(conn->ssl.handle, ssl_sessionid); /* Informational message */ infof (data, "SSL re-using session ID\n"); } } /* pass the raw socket into the SSL layers */ SSL_set_fd (conn->ssl.handle, conn->firstsocket); err = SSL_connect (conn->ssl.handle); Loading @@ -376,6 +555,13 @@ Curl_SSLConnect(struct connectdata *conn) infof (data, "SSL connection using %s\n", SSL_get_cipher(conn->ssl.handle)); if(!ssl_sessionid) { /* Since this is not a cached session ID, then we want to stach this one in the cache! */ Store_SSL_Session(conn); } /* Get server's certificate (note: beware of dynamic allocation) - opt */ /* major serious hack alert -- we should check certificates * to authenticate the server; otherwise we risk man-in-the-middle Loading lib/ssluse.h +10 −4 Original line number Diff line number Diff line Loading @@ -24,8 +24,14 @@ *****************************************************************************/ #include "urldata.h" CURLcode Curl_SSLConnect(struct connectdata *conn); /* Global SSL init */ void Curl_SSL_init(void); /* Global SSL cleanup */ void Curl_SSL_cleanup(void); void Curl_SSL_init(void); /* Global SSL init */ void Curl_SSL_cleanup(void); /* Global SSL cleanup */ /* init the SSL session ID cache */ CURLcode Curl_SSL_InitSessions(struct UrlData *, long); void Curl_SSL_Close(struct connectdata *conn); /* close a SSL connection */ /* tell the SSL stuff to close down all open information regarding connections (and thus session ID caching etc) */ int Curl_SSL_Close_All(struct UrlData *data); #endif lib/transfer.c +8 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ #include "http.h" #include "url.h" #include "getinfo.h" #include "ssluse.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> Loading Loading @@ -896,6 +897,13 @@ CURLcode Curl_perform(struct UrlData *data) /* we can't do anything wihout URL */ return CURLE_URL_MALFORMAT; #ifdef USE_SSLEAY /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could change the size) but before any transfer. */ Curl_SSL_InitSessions(data, data->ssl.numsessions); #endif data->followlocation=0; /* reset the location-follow counter */ data->bits.this_is_a_follow = FALSE; /* reset this */ Loading lib/url.c +9 −25 Original line number Diff line number Diff line Loading @@ -148,6 +148,11 @@ CURLcode Curl_close(struct UrlData *data) /* Loop through all open connections and kill them one by one */ while(-1 != ConnectionKillOne(data)); #ifdef USE_SSLEAY /* Close down all open info open SSL and sessions */ Curl_SSL_Close_All(data); #endif if(data->bits.proxystringalloc) { data->bits.proxystringalloc=FALSE;; free(data->proxy); Loading Loading @@ -242,6 +247,9 @@ CURLcode Curl_open(struct UrlData **curl) data->bits.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ data->progress.flags |= PGRS_HIDE; /* Set the default size of the SSL session ID cache */ data->ssl.numsessions = 5; /* create an array with connection data struct pointers */ data->numconnects = 5; /* hard-coded right now */ data->connects = (struct connectdata **) Loading Loading @@ -875,31 +883,7 @@ CURLcode Curl_disconnect(struct connectdata *conn) free(conn->path); #ifdef USE_SSLEAY if (conn->ssl.use) { /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its error queue removed. Since error queue data structures are allocated automatically for new threads, they must be freed when threads are terminated in oder to avoid memory leaks. */ ERR_remove_state(0); if(conn->ssl.handle) { (void)SSL_shutdown(conn->ssl.handle); SSL_set_connect_state(conn->ssl.handle); SSL_free (conn->ssl.handle); conn->ssl.handle = NULL; } if(conn->ssl.ctx) { SSL_CTX_free (conn->ssl.ctx); conn->ssl.ctx = NULL; } conn->ssl.use = FALSE; /* get back to ordinary socket usage */ } Curl_SSL_Close(conn); #endif /* USE_SSLEAY */ /* close possibly still open sockets */ Loading lib/urldata.h +11 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,13 @@ struct ssl_connect_data { #endif /* USE_SSLEAY */ }; /* information about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ void *sessionid; /* as returned from the SSL layer */ long age; /* just a number, the higher the more recent */ }; struct ssl_config_data { long version; /* what version the client wants to use */ long certverifyresult; /* result from the certificate verification */ Loading @@ -134,6 +141,10 @@ struct ssl_config_data { char *CAfile; /* cerficate to verify peer against */ char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ struct curl_ssl_session *session; /* array of 'numsessions' size */ long numsessions; /* SSL session id cache size */ long sessionage; /* number of the most recent session */ }; /**************************************************************************** Loading Loading
lib/ssluse.c +186 −0 Original line number Diff line number Diff line Loading @@ -278,10 +278,43 @@ void Curl_SSL_init(void) #endif } /* * This function is called when an SSL connection is closed. */ void Curl_SSL_Close(struct connectdata *conn) { if (conn->ssl.use) { /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its error queue removed. Since error queue data structures are allocated automatically for new threads, they must be freed when threads are terminated in oder to avoid memory leaks. */ ERR_remove_state(0); if(conn->ssl.handle) { (void)SSL_shutdown(conn->ssl.handle); SSL_set_connect_state(conn->ssl.handle); SSL_free (conn->ssl.handle); conn->ssl.handle = NULL; } if(conn->ssl.ctx) { SSL_CTX_free (conn->ssl.ctx); conn->ssl.ctx = NULL; } conn->ssl.use = FALSE; /* get back to ordinary socket usage */ } } /* Global cleanup */ void Curl_SSL_cleanup(void) { #ifdef USE_SSLEAY if(init_ssl) { /* only cleanup if we did a previous init */ Loading @@ -295,6 +328,140 @@ void Curl_SSL_cleanup(void) #endif } /* * This sets up a session cache to the specified size. */ CURLcode Curl_SSL_InitSessions(struct UrlData *data, long amount) { struct curl_ssl_session *session; if(data->ssl.session) /* this is just a precaution to prevent multiple inits */ return CURLE_OK; session = (struct curl_ssl_session *) malloc(amount * sizeof(struct curl_ssl_session)); if(!session) return CURLE_OUT_OF_MEMORY; /* "blank out" the newly allocated memory */ memset(session, 0, amount * sizeof(struct curl_ssl_session)); /* store the info in the SSL section */ data->ssl.numsessions = amount; data->ssl.session = session; data->ssl.sessionage = 1; /* this is brand new */ return CURLE_OK; } /* * Check if there's a session ID for the given connection in the cache, * and if there's one suitable, it is returned. */ static int Get_SSL_Session(struct connectdata *conn, SSL_SESSION **ssl_sessionid) { struct curl_ssl_session *check; struct UrlData *data = conn->data; long i; for(i=0; i< data->ssl.numsessions; i++) { check = &data->ssl.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; if(strequal(conn->name, check->name)) { /* yes, we have a session ID! */ data->ssl.sessionage++; /* increase general age */ check->age = data->ssl.sessionage; /* set this as used in this age */ *ssl_sessionid = check->sessionid; return FALSE; } } *ssl_sessionid = (SSL_SESSION *)NULL; return TRUE; } /* * Kill a single session ID entry in the cache. */ static int Kill_Single_Session(struct curl_ssl_session *session) { if(session->sessionid) { /* defensive check */ /* free the ID */ SSL_SESSION_free(session->sessionid); session->sessionid=NULL; session->age = 0; /* fresh */ free(session->name); session->name = NULL; /* no name */ return 0; /* ok */ } else return 1; } /* * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ int Curl_SSL_Close_All(struct UrlData *data) { int i; for(i=0; i< data->ssl.numsessions; i++) /* the single-killer function handles empty table slots */ Kill_Single_Session(&data->ssl.session[i]); /* free the cache data */ free(data->ssl.session); return 0; } /* * Extract the session id and store it in the session cache. */ static int Store_SSL_Session(struct connectdata *conn) { SSL_SESSION *ssl_sessionid; struct curl_ssl_session *store; int i; struct UrlData *data=conn->data; /* the mother of all structs */ int oldest_age=data->ssl.session[0].age; /* zero if unused */ /* ask OpenSSL, say please */ ssl_sessionid = SSL_get1_session(conn->ssl.handle); /* SSL_get1_session() will increment the reference count and the session will stay in memory until explicitly freed with SSL_SESSION_free(3), regardless of its state. */ /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* find an empty slot for us, or find the oldest */ for(i=0; (i<data->ssl.numsessions) && data->ssl.session[i].sessionid; i++) { if(data->ssl.session[i].age < oldest_age) { oldest_age = data->ssl.session[i].age; store = &data->ssl.session[i]; } } if(i == data->ssl.numsessions) /* cache is full, we must "kill" the oldest entry! */ Kill_Single_Session(store); else store = &data->ssl.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->age = data->ssl.sessionage; /* set current age */ store->name = strdup(conn->name); /* clone host name */ return 0; } /* ====================================================== */ CURLcode Loading @@ -307,6 +474,7 @@ Curl_SSLConnect(struct connectdata *conn) int err; char * str; SSL_METHOD *req_method; SSL_SESSION *ssl_sessionid=NULL; /* mark this is being ssl enabled from here on out. */ conn->ssl.use = TRUE; Loading Loading @@ -362,6 +530,17 @@ Curl_SSLConnect(struct connectdata *conn) conn->ssl.server_cert = 0x0; if(!conn->bits.reuse) { /* We're not re-using a connection, check if there's a cached ID we can/should use here! */ if(!Get_SSL_Session(conn, &ssl_sessionid)) { /* we got a session id, use it! */ SSL_set_session(conn->ssl.handle, ssl_sessionid); /* Informational message */ infof (data, "SSL re-using session ID\n"); } } /* pass the raw socket into the SSL layers */ SSL_set_fd (conn->ssl.handle, conn->firstsocket); err = SSL_connect (conn->ssl.handle); Loading @@ -376,6 +555,13 @@ Curl_SSLConnect(struct connectdata *conn) infof (data, "SSL connection using %s\n", SSL_get_cipher(conn->ssl.handle)); if(!ssl_sessionid) { /* Since this is not a cached session ID, then we want to stach this one in the cache! */ Store_SSL_Session(conn); } /* Get server's certificate (note: beware of dynamic allocation) - opt */ /* major serious hack alert -- we should check certificates * to authenticate the server; otherwise we risk man-in-the-middle Loading
lib/ssluse.h +10 −4 Original line number Diff line number Diff line Loading @@ -24,8 +24,14 @@ *****************************************************************************/ #include "urldata.h" CURLcode Curl_SSLConnect(struct connectdata *conn); /* Global SSL init */ void Curl_SSL_init(void); /* Global SSL cleanup */ void Curl_SSL_cleanup(void); void Curl_SSL_init(void); /* Global SSL init */ void Curl_SSL_cleanup(void); /* Global SSL cleanup */ /* init the SSL session ID cache */ CURLcode Curl_SSL_InitSessions(struct UrlData *, long); void Curl_SSL_Close(struct connectdata *conn); /* close a SSL connection */ /* tell the SSL stuff to close down all open information regarding connections (and thus session ID caching etc) */ int Curl_SSL_Close_All(struct UrlData *data); #endif
lib/transfer.c +8 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ #include "http.h" #include "url.h" #include "getinfo.h" #include "ssluse.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> Loading Loading @@ -896,6 +897,13 @@ CURLcode Curl_perform(struct UrlData *data) /* we can't do anything wihout URL */ return CURLE_URL_MALFORMAT; #ifdef USE_SSLEAY /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could change the size) but before any transfer. */ Curl_SSL_InitSessions(data, data->ssl.numsessions); #endif data->followlocation=0; /* reset the location-follow counter */ data->bits.this_is_a_follow = FALSE; /* reset this */ Loading
lib/url.c +9 −25 Original line number Diff line number Diff line Loading @@ -148,6 +148,11 @@ CURLcode Curl_close(struct UrlData *data) /* Loop through all open connections and kill them one by one */ while(-1 != ConnectionKillOne(data)); #ifdef USE_SSLEAY /* Close down all open info open SSL and sessions */ Curl_SSL_Close_All(data); #endif if(data->bits.proxystringalloc) { data->bits.proxystringalloc=FALSE;; free(data->proxy); Loading Loading @@ -242,6 +247,9 @@ CURLcode Curl_open(struct UrlData **curl) data->bits.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ data->progress.flags |= PGRS_HIDE; /* Set the default size of the SSL session ID cache */ data->ssl.numsessions = 5; /* create an array with connection data struct pointers */ data->numconnects = 5; /* hard-coded right now */ data->connects = (struct connectdata **) Loading Loading @@ -875,31 +883,7 @@ CURLcode Curl_disconnect(struct connectdata *conn) free(conn->path); #ifdef USE_SSLEAY if (conn->ssl.use) { /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its error queue removed. Since error queue data structures are allocated automatically for new threads, they must be freed when threads are terminated in oder to avoid memory leaks. */ ERR_remove_state(0); if(conn->ssl.handle) { (void)SSL_shutdown(conn->ssl.handle); SSL_set_connect_state(conn->ssl.handle); SSL_free (conn->ssl.handle); conn->ssl.handle = NULL; } if(conn->ssl.ctx) { SSL_CTX_free (conn->ssl.ctx); conn->ssl.ctx = NULL; } conn->ssl.use = FALSE; /* get back to ordinary socket usage */ } Curl_SSL_Close(conn); #endif /* USE_SSLEAY */ /* close possibly still open sockets */ Loading
lib/urldata.h +11 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,13 @@ struct ssl_connect_data { #endif /* USE_SSLEAY */ }; /* information about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ void *sessionid; /* as returned from the SSL layer */ long age; /* just a number, the higher the more recent */ }; struct ssl_config_data { long version; /* what version the client wants to use */ long certverifyresult; /* result from the certificate verification */ Loading @@ -134,6 +141,10 @@ struct ssl_config_data { char *CAfile; /* cerficate to verify peer against */ char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ struct curl_ssl_session *session; /* array of 'numsessions' size */ long numsessions; /* SSL session id cache size */ long sessionage; /* number of the most recent session */ }; /**************************************************************************** Loading