From 6e619393824922118317689ef59a73c556b7ef98 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 7 Apr 2005 15:27:13 +0000 Subject: GnuTLS support added. There's now a "generic" SSL layer that we use all over internally, with code provided by sslgen.c. All SSL-layer-specific code is then written in ssluse.c (for OpenSSL) and gtls.c (for GnuTLS). As far as possible, internals should not need to know what SSL layer that is in use. Building with GnuTLS currently makes two test cases fail. TODO.gnutls contains a few known outstanding issues for the GnuTLS support. GnuTLS support is enabled with configure --with-gnutls --- lib/gtls.c | 464 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 lib/gtls.c (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c new file mode 100644 index 000000000..f3ab78c3c --- /dev/null +++ b/lib/gtls.c @@ -0,0 +1,464 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + +/* + * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code + * but sslgen.c should ever call or use these functions. + * + * Note: don't use the GnuTLS' *_t variable type names in this source code, + * since they were not present in 1.0.X. + */ + +#include "setup.h" +#ifdef USE_GNUTLS +#include +#include + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "gtls.h" +#include "sslgen.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#define _MPRINTF_REPLACE /* use our functions only */ +#include +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* Global GnuTLS init, called from Curl_ssl_init() */ +int Curl_gtls_init(void) +{ + gnutls_global_init(); + return 1; +} + +int Curl_gtls_cleanup(void) +{ + gnutls_global_deinit(); + return 1; +} + +static void showtime(struct SessionHandle *data, + const char *text, + time_t stamp) +{ + struct tm *tm; +#ifdef HAVE_GMTIME_R + struct tm buffer; + tm = (struct tm *)gmtime_r(&stamp, &buffer); +#else + tm = gmtime(&stamp); +#endif + snprintf(data->state.buffer, + BUFSIZE, + "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", + text, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + infof(data, "%s", data->state.buffer); +} + + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic. + */ +CURLcode +Curl_gtls_connect(struct connectdata *conn, + int sockindex) + +{ + const int cert_type_priority[3] = { GNUTLS_CRT_X509, 0 }; + struct SessionHandle *data = conn->data; + gnutls_session session; + int rc; + unsigned int cert_list_size; + const gnutls_datum *chainp; + unsigned int verify_status; + gnutls_x509_crt x509_cert; + char certbuf[256]; /* big enough? */ + size_t size; + unsigned int algo; + unsigned int bits; + time_t clock; + const char *ptr; + void *ssl_sessionid; + size_t ssl_idsize; + + /* GnuTLS only supports TLSv1 (and SSLv3?) */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* allocate a cred struct */ + rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); + if(rc < 0) { + failf(data, "gnutls_cert_all_cred() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* set the trusted CA cert bundle file */ + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + + /* Initialize TLS session as a client */ + rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); + if(rc) { + failf(data, "gnutls_init() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* convenient assign */ + session = conn->ssl[sockindex].session; + + /* Use default priorities */ + rc = gnutls_set_default_priority(session); + if(rc < 0) + return CURLE_SSL_CONNECT_ERROR; + + /* Sets the priority on the certificate types supported by gnutls. Priority + is higher for types specified before others. After specifying the types + you want, you must append a 0. */ + rc = gnutls_certificate_type_set_priority(session, cert_type_priority); + if(rc < 0) + return CURLE_SSL_CONNECT_ERROR; + + /* put the anonymous credentials to the current session */ + rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + conn->ssl[sockindex].cred); + + /* set the connection handle (file descriptor for the socket) */ + gnutls_transport_set_ptr(session, + (gnutls_transport_ptr)conn->sock[sockindex]); + + /* This might be a reconnect, so we check for a session ID in the cache + to speed up things */ + + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + + do { + rc = gnutls_handshake(session); + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + long timeout_ms; + long has_passed; + + if(data->set.timeout || data->set.connecttimeout) { + /* get the most strict timeout of the ones converted to milliseconds */ + if(data->set.timeout && + (data->set.timeout>data->set.connecttimeout)) + timeout_ms = data->set.timeout*1000; + else + timeout_ms = data->set.connecttimeout*1000; + } + else + timeout_ms = DEFAULT_CONNECT_TIMEOUT; + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + + /* subtract the passed time */ + timeout_ms -= has_passed; + + if(timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEOUTED; + } + + rc = Curl_select(conn->sock[sockindex], + conn->sock[sockindex], (int)timeout_ms); + if(rc > 0) + /* reabable or writable, go loop*/ + continue; + else if(0 == rc) { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); + return CURLE_SSL_CONNECT_ERROR; + } + } + else + break; + } while(1); + + if (rc < 0) { + failf(data, "gnutls_handshake() failed: %d", rc); + /* gnutls_perror(ret); */ + return CURLE_SSL_CONNECT_ERROR; + } + + /* This function will return the peer's raw certificate (chain) as sent by + the peer. These certificates are in raw format (DER encoded for + X.509). In case of a X.509 then a certificate list may be present. The + first certificate in the list is the peer's certificate, following the + issuer's certificate, then the issuer's issuer etc. */ + + chainp = gnutls_certificate_get_peers(session, &cert_list_size); + if(!chainp) { + if(data->set.ssl.verifyhost) { + failf(data, "failed to get server cert"); + return CURLE_SSL_PEER_CERTIFICATE; + } + infof(data, "\t common name: WARNING couldn't obtain\n"); + } + + /* This function will try to verify the peer's certificate and return its + status (trusted, invalid etc.). The value of status should be one or more + of the gnutls_certificate_status_t enumerated elements bitwise or'd. To + avoid denial of service attacks some default upper limits regarding the + certificate key size and chain size are set. To override them use + gnutls_certificate_set_verify_limits(). */ + + rc = gnutls_certificate_verify_peers2(session, &verify_status); + if (rc < 0) { + failf(data, "server cert verify failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* verify_status is a bitmask of gnutls_certificate_status bits */ + if(verify_status & GNUTLS_CERT_INVALID) { + if (data->set.ssl.verifypeer) { + failf(data, "server certificate verification failed. CAfile: %s", + data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); + return CURLE_SSL_CACERT; + } + else + infof(data, "\t server certificate verification FAILED\n"); + } + else + infof(data, "\t server certificate verification OK\n"); + + /* initialize an X.509 certificate structure. */ + gnutls_x509_crt_init(&x509_cert); + + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + + size=sizeof(certbuf); + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + TRUE, /* give to me raw please */ + certbuf, + &size); + + /* This function will check if the given certificate's subject matches the + given hostname. This is a basic implementation of the matching described + in RFC2818 (HTTPS), which takes into account wildcards, and the subject + alternative name PKIX extension. Returns non zero on success, and zero on + failure. */ + rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); + + if(!rc) { + if (data->set.ssl.verifyhost > 1) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target host name '%s'", certbuf, conn->host.dispname); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t common name: %s (does not match '%s')\n", + certbuf, conn->host.dispname); + } + else + infof(data, "\t common name: %s (matched)\n", certbuf); + + /* Show: + + - ciphers used + - subject + - start date + - expire date + - common name + - issuer + + */ + + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, "\t certificate public key: %s\n", + gnutls_pk_algorithm_get_name(algo)); + + /* version of the X.509 certificate. */ + infof(data, "\t certificate version: #%d\n", + gnutls_x509_crt_get_version(x509_cert)); + + + size = sizeof(certbuf); + gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); + infof(data, "\t subject: %s\n", certbuf); + + clock = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", clock); + + clock = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", clock); + + size = sizeof(certbuf); + gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); + infof(data, "\t issuer: %s\n", certbuf); + + gnutls_x509_crt_deinit(x509_cert); + + /* compression algorithm (if any) */ + ptr = gnutls_compression_get_name(gnutls_compression_get(session)); + /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ + infof(data, "\t compression: %s\n", ptr); + + /* the name of the cipher used. ie 3DES. */ + ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); + infof(data, "\t cipher: %s\n", ptr); + + /* the MAC algorithms name. ie SHA1 */ + ptr = gnutls_mac_get_name(gnutls_mac_get(session)); + infof(data, "\t MAC: %s\n", ptr); + + if(!ssl_sessionid) { + /* this session was not previously in the cache, add it now */ + + /* get the session ID data size */ + gnutls_session_get_data(session, NULL, &ssl_idsize); + ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */ + + if(ssl_sessionid) { + /* extract session ID to the allocated buffer */ + gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize); + + /* store this session id */ + return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize); + } + } + + return CURLE_OK; +} + + +/* return number of sent (non-SSL) bytes */ +int Curl_gtls_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len) +{ + int rc; + rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + + return rc; +} + +void Curl_gtls_close_all(struct SessionHandle *data) +{ + /* FIX: make the OpenSSL code more generic and use parts of it here */ + (void)data; +} + +static void close_one(struct connectdata *conn, + int index) +{ + gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->ssl[index].session); + gnutls_certificate_free_credentials(conn->ssl[index].cred); +} + +void Curl_gtls_close(struct connectdata *conn) +{ + if(conn->ssl[0].use) + close_one(conn, 0); + if(conn->ssl[1].use) + close_one(conn, 1); +} + +/* + * If the read would block we return -1 and set 'wouldblock' to TRUE. + * Otherwise we return the amount of data read. Other errors should return -1 + * and set 'wouldblock' to FALSE. + */ +ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + bool *wouldblock) +{ + ssize_t ret; + + ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); + if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { + *wouldblock = TRUE; + return -1; + } + + *wouldblock = FALSE; + if (!ret) { + failf(conn->data, "Peer closed the TLS connection"); + return -1; + } + + if (ret < 0) { + failf(conn->data, "GnuTLS recv error (%d): %s", + (int)ret, gnutls_strerror(ret)); + return -1; + } + + return ret; +} + +void Curl_gtls_session_free(void *ptr) +{ + free(ptr); +} + +size_t Curl_gtls_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL)); +} + +#endif /* USE_GNUTLS */ -- cgit v1.2.1 From b9f1d43921b0384fc2843d2eabd80c33fb490760 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 7 Apr 2005 22:47:43 +0000 Subject: Unfortunately, if a ca file name is set the function fails for whatever reason (missing file, bad file, etc), gnutls will no longer handshake properly but it just loops forever. Therefore, we must return error if we get an error when setting the CA cert file name. This is not the same behaviour as with OpenSSL. Question/report posted to the help-gnutls mailing list, April 8 2005. --- lib/gtls.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f3ab78c3c..e8f5deb7a 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -135,10 +135,26 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - /* set the trusted CA cert bundle file */ - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, - GNUTLS_X509_FMT_PEM); + if(data->set.ssl.CAfile) { + /* set the trusted CA cert bundle file */ + + /* + * Unfortunately, if a file name is set here and this function fails for + * whatever reason (missing file, bad file, etc), gnutls will no longer + * handshake properly but it just loops forever. Therefore, we must return + * error here if we get an error when setting the CA cert file name. + * + * (Question/report posted to the help-gnutls mailing list, April 8 2005) + */ + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + if(rc) { + failf(data, "error reading the ca cert file %s", + data->set.ssl.CAfile); + return CURLE_SSL_CACERT; + } + } /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); @@ -404,8 +420,10 @@ void Curl_gtls_close_all(struct SessionHandle *data) static void close_one(struct connectdata *conn, int index) { - gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[index].session); + if(conn->ssl[index].session) { + gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->ssl[index].session); + } gnutls_certificate_free_credentials(conn->ssl[index].cred); } -- cgit v1.2.1 From 80fe93bc338b3795a4ac32f1d15bc71861100ffd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 9 Apr 2005 21:38:14 +0000 Subject: OK, I must've been halucinating or something because I no longer see the bug I thought I saw before when I changed this...! --- lib/gtls.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index e8f5deb7a..a87c3a03b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -57,10 +57,25 @@ /* The last #include file should be: */ #include "memdebug.h" +/* Enable GnuTLS debugging by defining GTLSDEBUG */ +/*#define GTLSDEBUG */ + +#ifdef GTLSDEBUG +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} +#endif + + /* Global GnuTLS init, called from Curl_ssl_init() */ int Curl_gtls_init(void) { gnutls_global_init(); +#ifdef GTLSDEBUG + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(2); +#endif return 1; } @@ -95,7 +110,6 @@ static void showtime(struct SessionHandle *data, infof(data, "%s", data->state.buffer); } - /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. @@ -105,7 +119,7 @@ Curl_gtls_connect(struct connectdata *conn, int sockindex) { - const int cert_type_priority[3] = { GNUTLS_CRT_X509, 0 }; + const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; struct SessionHandle *data = conn->data; gnutls_session session; int rc; @@ -135,25 +149,13 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - if(data->set.ssl.CAfile) { - /* set the trusted CA cert bundle file */ - - /* - * Unfortunately, if a file name is set here and this function fails for - * whatever reason (missing file, bad file, etc), gnutls will no longer - * handshake properly but it just loops forever. Therefore, we must return - * error here if we get an error when setting the CA cert file name. - * - * (Question/report posted to the help-gnutls mailing list, April 8 2005) - */ - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, - GNUTLS_X509_FMT_PEM); - if(rc) { - failf(data, "error reading the ca cert file %s", - data->set.ssl.CAfile); - return CURLE_SSL_CACERT; - } + /* set the trusted CA cert bundle file */ + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + if(rc) { + infof(data, "error reading the ca cert file %s", + data->set.ssl.CAfile); } /* Initialize TLS session as a client */ -- cgit v1.2.1 From f09e479fd62e62f7f81f6219c02b14c96cff6120 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 9 Apr 2005 22:33:14 +0000 Subject: Blah, revert my removal of the extra check since the problem is there for real. Archived thread of the help-gnutls mailing list regarding this problem: http://lists.gnu.org/archive/html/help-gnutls/2005-04/msg00000.html (and I _am_ sorry for my confused behaviour on this problem.) --- lib/gtls.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a87c3a03b..bc7cd27e3 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -149,13 +149,25 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - /* set the trusted CA cert bundle file */ - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, - GNUTLS_X509_FMT_PEM); - if(rc) { - infof(data, "error reading the ca cert file %s", - data->set.ssl.CAfile); + if(data->set.ssl.CAfile) { + /* set the trusted CA cert bundle file */ + + /* + * Unfortunately, if a file name is set here and this function fails for + * whatever reason (missing file, bad file, etc), gnutls will no longer + * handshake properly but it just loops forever. Therefore, we must return + * error here if we get an error when setting the CA cert file name. + * + * (Question/report posted to the help-gnutls mailing list, April 8 2005) + */ + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + if(rc) { + failf(data, "error reading the ca cert file %s", + data->set.ssl.CAfile); + return CURLE_SSL_CACERT; + } } /* Initialize TLS session as a client */ -- cgit v1.2.1 From 316adac511b95f0ccab565275af11dd5a62611d9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 13 Apr 2005 12:38:01 +0000 Subject: don't bail out just because the ca file has a problem, it might be OK --- lib/gtls.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index bc7cd27e3..0ec101ce6 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -145,28 +145,18 @@ Curl_gtls_connect(struct connectdata *conn, /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); if(rc < 0) { - failf(data, "gnutls_cert_all_cred() failed: %d", rc); + failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ - - /* - * Unfortunately, if a file name is set here and this function fails for - * whatever reason (missing file, bad file, etc), gnutls will no longer - * handshake properly but it just loops forever. Therefore, we must return - * error here if we get an error when setting the CA cert file name. - * - * (Question/report posted to the help-gnutls mailing list, April 8 2005) - */ rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); if(rc) { - failf(data, "error reading the ca cert file %s", - data->set.ssl.CAfile); - return CURLE_SSL_CACERT; + infof(data, "error reading ca cert file %s (%s)", + data->set.ssl.CAfile, gnutls_strerror(rc)); } } -- cgit v1.2.1 From e9d068b913fd972bda6d1c2366bb1dcd6eb8e31f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 13 Apr 2005 21:17:05 +0000 Subject: oops, only negative numbers are errors --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 0ec101ce6..fff5d5e62 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -154,8 +154,8 @@ Curl_gtls_connect(struct connectdata *conn, rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); - if(rc) { - infof(data, "error reading ca cert file %s (%s)", + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); } } -- cgit v1.2.1 From 543fbe14eee5dbbd81f1e9ec2004d5f327504367 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 22 Apr 2005 20:56:26 +0000 Subject: Fixed the CN extraction --- lib/gtls.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index fff5d5e62..7ca8a0f42 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -308,9 +308,13 @@ Curl_gtls_connect(struct connectdata *conn, size=sizeof(certbuf); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ - TRUE, /* give to me raw please */ + FALSE, certbuf, &size); + if(rc) { + infof(data, "error fetching CN from cert:%s\n", + gnutls_strerror(rc)); + } /* This function will check if the given certificate's subject matches the given hostname. This is a basic implementation of the matching described -- cgit v1.2.1 From 432dfe2b8ff14dad451ec25f0bee09d454893324 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Aug 2005 07:40:13 +0000 Subject: Fixed CA cert verification using GnuTLS with the default bundle, which previously failed due to GnuTLS not allowing x509 v1 CA certs by default. --- lib/gtls.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 7ca8a0f42..dbe3d1f77 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -151,13 +151,18 @@ Curl_gtls_connect(struct connectdata *conn, if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ + gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); - if(rc < 0) { + if(rc < 0) infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); - } + else + infof(data, "found %d certificates in %s\n", + rc, data->set.ssl.CAfile); } /* Initialize TLS session as a client */ -- cgit v1.2.1 From c890149c8c144e6eb226d4ebf1723d203e1859ff Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 22 Oct 2005 21:05:07 +0000 Subject: Dima Barsky reported a problem with GnuTLS-enabled libcurl in bug report #1334338 (http://curl.haxx.se/bug/view.cgi?id=1334338). When reading an SSL stream from a server and the server requests a "rehandshake", the current code simply returns this as an error. I have no good way to test this, but I've added a crude attempt of dealing with this situation slightly better - it makes a blocking handshake if this happens. Done like this because fixing this the "proper" way (that would handshake asynchronously) will require quite some work and I really need a good way to test this to do such a change. --- lib/gtls.c | 136 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 55 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index dbe3d1f77..aa9d98dfa 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -110,6 +110,72 @@ static void showtime(struct SessionHandle *data, infof(data, "%s", data->state.buffer); } +/* this function does a BLOCKING SSL/TLS (re-)handshake */ +static CURLcode handshake(struct connectdata *conn, + gnutls_session session, + int sockindex, + bool duringconnect) +{ + struct SessionHandle *data = conn->data; + int rc; + + do { + rc = gnutls_handshake(session); + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + long timeout_ms = DEFAULT_CONNECT_TIMEOUT; + long has_passed; + + if(duringconnect && data->set.connecttimeout) + timeout_ms = data->set.connecttimeout*1000; + + if(data->set.timeout) { + /* get the strictest timeout of the ones converted to milliseconds */ + if((data->set.timeout*1000) < timeout_ms) + timeout_ms = data->set.timeout*1000; + } + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + + /* subtract the passed time */ + timeout_ms -= has_passed; + + if(timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEOUTED; + } + + rc = Curl_select(conn->sock[sockindex], + conn->sock[sockindex], (int)timeout_ms); + if(rc > 0) + /* reabable or writable, go loop*/ + continue; + else if(0 == rc) { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); + return CURLE_SSL_CONNECT_ERROR; + } + } + else + break; + } while(1); + + if (rc < 0) { + failf(data, "gnutls_handshake() failed: %d", rc); + /* gnutls_perror(ret); */ + return CURLE_SSL_CONNECT_ERROR; + } + + return CURLE_OK; +} + /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. @@ -206,61 +272,10 @@ Curl_gtls_connect(struct connectdata *conn, infof (data, "SSL re-using session ID\n"); } - do { - rc = gnutls_handshake(session); - - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - long timeout_ms; - long has_passed; - - if(data->set.timeout || data->set.connecttimeout) { - /* get the most strict timeout of the ones converted to milliseconds */ - if(data->set.timeout && - (data->set.timeout>data->set.connecttimeout)) - timeout_ms = data->set.timeout*1000; - else - timeout_ms = data->set.connecttimeout*1000; - } - else - timeout_ms = DEFAULT_CONNECT_TIMEOUT; - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - - /* subtract the passed time */ - timeout_ms -= has_passed; - - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEOUTED; - } - - rc = Curl_select(conn->sock[sockindex], - conn->sock[sockindex], (int)timeout_ms); - if(rc > 0) - /* reabable or writable, go loop*/ - continue; - else if(0 == rc) { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); - return CURLE_SSL_CONNECT_ERROR; - } - } - else - break; - } while(1); - - if (rc < 0) { - failf(data, "gnutls_handshake() failed: %d", rc); - /* gnutls_perror(ret); */ - return CURLE_SSL_CONNECT_ERROR; - } + rc = handshake(conn, session, sockindex, TRUE); + if(rc) + /* handshake() sets its own error message with failf() */ + return rc; /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for @@ -467,6 +482,17 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ return -1; } + if(ret == GNUTLS_E_REHANDSHAKE) { + /* BLOCKING call, this is bad but a work-around for now. Fixing this "the + proper way" takes a whole lot of work. */ + CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE); + if(rc) + /* handshake() writes error message on its own */ + return rc; + *wouldblock = TRUE; /* then return as if this was a wouldblock */ + return -1; + } + *wouldblock = FALSE; if (!ret) { failf(conn->data, "Peer closed the TLS connection"); -- cgit v1.2.1 From 5e3836055ff8697c0d0ea514fdc9e16ca4b3c424 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 11 Nov 2005 23:20:07 +0000 Subject: Dima Barsky patched problem #1348930: the GnuTLS code completely ignored client certificates! (http://curl.haxx.se/bug/view.cgi?id=1348930). --- lib/gtls.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index aa9d98dfa..cc33deabf 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -176,6 +176,18 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OK; } +static gnutls_x509_crt_fmt_t do_file_type(const char *type) +{ + if(!type || !type[0]) + return GNUTLS_X509_FMT_PEM; + if(curl_strequal(type, "PEM")) + return GNUTLS_X509_FMT_PEM; + if(curl_strequal(type, "DER")) + return GNUTLS_X509_FMT_DER; + return -1; +} + + /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. @@ -253,7 +265,17 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) return CURLE_SSL_CONNECT_ERROR; - /* put the anonymous credentials to the current session */ + if(data->set.cert) { + if( gnutls_certificate_set_x509_key_file( + conn->ssl[sockindex].cred, data->set.cert, + data->set.key != 0 ? data->set.key : data->set.cert, + do_file_type(data->set.cert_type) ) ) { + failf(data, "error reading X.509 key or certificate file"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* put the credentials to the current session */ rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); -- cgit v1.2.1 From 7e81c35cdc967e8babb73cd6f7e70b81ed404186 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 13 Nov 2005 23:04:28 +0000 Subject: to build with old gnutls verions, don't use the *_t types --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index cc33deabf..5d3959cce 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -176,7 +176,7 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OK; } -static gnutls_x509_crt_fmt_t do_file_type(const char *type) +static gnutls_x509_crt_fmt do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; -- cgit v1.2.1 From 758f6eed5169f20635c410077b840c1ffb741ddb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 4 May 2006 06:00:40 +0000 Subject: Mark Eichin submitted bug report #1480821 (http://curl.haxx.se/bug/view.cgi?id=1480821) He found and identified a problem with how libcurl dealt with GnuTLS and a case where gnutls returned GNUTLS_E_AGAIN indicating it would block. It would then return an unexpected return code, making Curl_ssl_send() confuse the upper layer - causing random 28 bytes trash data to get inserted in the transfered stream. The proper fix was to make the Curl_gtls_send() function return the proper return codes that the callers would expect. The Curl_ossl_send() function already did this. --- lib/gtls.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 5d3959cce..4cf78080b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -458,6 +458,12 @@ int Curl_gtls_send(struct connectdata *conn, int rc; rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + if(rc < 0 ) { + if(rc == GNUTLS_E_AGAIN) + return 0; /* EWOULDBLOCK equivalent */ + rc = -1; /* generic error code for send failure */ + } + return rc; } -- cgit v1.2.1 From 9bece2b313ec75901410b52056adbaae8c49e508 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 5 May 2006 10:24:27 +0000 Subject: additional renames of Curl_ourerrno => Curl_sockerrno --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 4cf78080b..dc33dc600 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -159,7 +159,7 @@ static CURLcode handshake(struct connectdata *conn, } else { /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); return CURLE_SSL_CONNECT_ERROR; } } -- cgit v1.2.1 From 455087faaea688579584375308a696e602c1e8d2 Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Wed, 16 Aug 2006 17:05:54 +0000 Subject: Use gnutls_strerror() for clearer error message. --- lib/gtls.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index dc33dc600..b202adfd4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -168,8 +168,7 @@ static CURLcode handshake(struct connectdata *conn, } while(1); if (rc < 0) { - failf(data, "gnutls_handshake() failed: %d", rc); - /* gnutls_perror(ret); */ + failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } -- cgit v1.2.1 From 4e717cdb300adeff3b259b3619b29a944c2960a8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 21 Oct 2006 11:32:05 +0000 Subject: Armel Asselin separated CA cert verification problems from problems with reading the (local) CA cert file to let users easier pinpoint the actual problem. CURLE_SSL_CACERT_BADFILE (77) is the new libcurl error code. --- lib/gtls.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index b202adfd4..02680d02b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -234,9 +234,12 @@ Curl_gtls_connect(struct connectdata *conn, rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); - if(rc < 0) + if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); + if (data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } else infof(data, "found %d certificates in %s\n", rc, data->set.ssl.CAfile); -- cgit v1.2.1 From be0d17e812053bddd99e1d330c429399f17aee44 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Nov 2006 21:34:43 +0000 Subject: cleaned up Curl_write() and the sub functions it uses for various protocols. They all now return ssize_t to Curl_write(). Unfortunately, Curl_read() is in a sorrier state but it too would benefit from a similar cleanup. --- lib/gtls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 02680d02b..ee7612028 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -452,13 +452,12 @@ Curl_gtls_connect(struct connectdata *conn, /* return number of sent (non-SSL) bytes */ -int Curl_gtls_send(struct connectdata *conn, +ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, void *mem, size_t len) { - int rc; - rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); if(rc < 0 ) { if(rc == GNUTLS_E_AGAIN) -- cgit v1.2.1 From fcccf9aa0d93c666e8ae31ebdde716cddd6b4482 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 16 Dec 2006 21:33:51 +0000 Subject: Brendan Jurd provided a fix that now prevents libcurl from getting a SIGPIPE during certain conditions when GnuTLS is used. --- lib/gtls.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index ee7612028..bbd87161d 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -67,6 +67,23 @@ static void tls_log_func(int level, const char *str) } #endif +/* + * Custom push and pull callback functions used by GNU TLS to read and write + * to the socket. These functions are simple wrappers to send() and recv() + * (although here using the sread/swrite macros as defined by setup_once.h). + * We use custom functions rather than the GNU TLS defaults because it allows + * us to get specific about the fourth "flags" argument, and to use arbitrary + * private data with gnutls_transport_set_ptr if we wish. + */ +static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) +{ + return swrite(s, buf, len); +} + +static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) +{ + return sread(s, buf, len); +} /* Global GnuTLS init, called from Curl_ssl_init() */ int Curl_gtls_init(void) @@ -285,6 +302,13 @@ Curl_gtls_connect(struct connectdata *conn, gnutls_transport_set_ptr(session, (gnutls_transport_ptr)conn->sock[sockindex]); + /* register callback functions to send and receive data. */ + gnutls_transport_set_push_function(session, Curl_gtls_push); + gnutls_transport_set_pull_function(session, Curl_gtls_pull); + + /* lowat must be set to zero when using custom push and pull functions. */ + gnutls_transport_set_lowat(session, 0); + /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ -- cgit v1.2.1 From 4750e6f3c5fd42e19998242ddb63d7d5506b9fd9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 5 Jan 2007 23:11:14 +0000 Subject: - Linus Nielsen Feltzing introduced the --ftp-ssl-ccc command line option to curl that uses the new CURLOPT_FTP_SSL_CCC option in libcurl. If enabled, it will make libcurl shutdown SSL/TLS after the authentication is done on a FTP-SSL operation. --- lib/gtls.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index bbd87161d..250ecada4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -516,6 +516,72 @@ void Curl_gtls_close(struct connectdata *conn) close_one(conn, 1); } +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) +{ + int result; + int retval = 0; + struct SessionHandle *data = conn->data; + int done = 0; + ssize_t nread; + char buf[120]; + + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(conn->ssl[sockindex].session) { + while(!done) { + int what = Curl_select(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(conn->ssl[sockindex].session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = 1; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); + break; + default: + retval = -1; + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + retval = -1; + done = 1; + } + } + gnutls_deinit(conn->ssl[sockindex].session); + } + gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); + + conn->ssl[sockindex].session = NULL; + conn->ssl[sockindex].use = FALSE; + + return retval; +} + /* * If the read would block we return -1 and set 'wouldblock' to TRUE. * Otherwise we return the amount of data read. Other errors should return -1 -- cgit v1.2.1 From 91386937ff120d11f7bf24dc487f00751362a61c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 5 Feb 2007 22:51:32 +0000 Subject: - Michael Wallner provided a patch that adds support for CURLOPT_TIMEOUT_MS and CURLOPT_CONNECTTIMEOUT_MS that, as their names should hint, do the timeouts with millisecond resolution instead. The only restriction to that is the alarm() (sometimes) used to abort name resolves as that uses full seconds. I fixed the FTP response timeout part of the patch. Internally we now count and keep the timeouts in milliseconds but it also means we multiply set timeouts with 1000. The effect of this is that no timeout can be set to more than 2^31 milliseconds (on 32 bit systems), which equals 24.86 days. We probably couldn't before either since the code did *1000 on the timeout values on several places already. --- lib/gtls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 250ecada4..977263b12 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -144,12 +144,12 @@ static CURLcode handshake(struct connectdata *conn, long has_passed; if(duringconnect && data->set.connecttimeout) - timeout_ms = data->set.connecttimeout*1000; + timeout_ms = data->set.connecttimeout; if(data->set.timeout) { /* get the strictest timeout of the ones converted to milliseconds */ - if((data->set.timeout*1000) < timeout_ms) - timeout_ms = data->set.timeout*1000; + if(data->set.timeout) < timeout_ms) + timeout_ms = data->set.timeout; } /* Evaluate in milliseconds how much time that has passed */ -- cgit v1.2.1 From a1d598399146984c99baa46db148e87c75261033 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Fri, 16 Feb 2007 18:19:35 +0000 Subject: use macros ERRNO, SET_ERRNO(), SOCKERRNO and SET_SOCKERRNO() for errno handling --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 977263b12..e4d43d6f8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -176,7 +176,7 @@ static CURLcode handshake(struct connectdata *conn, } else { /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + failf(data, "select on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } } @@ -567,7 +567,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) } else { /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + failf(data, "select on SSL socket, errno: %d", SOCKERRNO); retval = -1; done = 1; } -- cgit v1.2.1 From ec1b3513176b6bac4706de2dc6468dcff3a2e63f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 19 Feb 2007 11:47:04 +0000 Subject: fixed code to compile and removed one warning --- lib/gtls.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index e4d43d6f8..daf69aafe 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -148,7 +148,7 @@ static CURLcode handshake(struct connectdata *conn, if(data->set.timeout) { /* get the strictest timeout of the ones converted to milliseconds */ - if(data->set.timeout) < timeout_ms) + if(data->set.timeout < timeout_ms) timeout_ms = data->set.timeout; } @@ -526,7 +526,6 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) int retval = 0; struct SessionHandle *data = conn->data; int done = 0; - ssize_t nread; char buf[120]; /* This has only been tested on the proftpd server, and the mod_tls code -- cgit v1.2.1 From 2f5e99ca02b6716fdac59c299ab7738a2077743d Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Tue, 20 Feb 2007 22:02:11 +0000 Subject: New FTP CCC functionality - adds passive and active mode to accomodate for different server behaviour --- lib/gtls.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index daf69aafe..f8c103450 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -533,6 +533,9 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR); + if(conn->ssl[sockindex].session) { while(!done) { int what = Curl_select(conn->sock[sockindex], -- cgit v1.2.1 From c514a2a89aa1c1e06b70405eedb4e1f70b27fd10 Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Mon, 26 Feb 2007 04:24:26 +0000 Subject: Removed inclusion of and in .c-files since they're already included through "setup.h". --- lib/gtls.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f8c103450..3413a0709 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -37,9 +37,6 @@ #include #include #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif #ifdef HAVE_SYS_SOCKET_H #include #endif -- cgit v1.2.1 From fba4cd0e625cdba3561b3530317ba87ae348aeaf Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 26 Mar 2007 23:23:46 +0000 Subject: Internal function Curl_select() renamed to Curl_socket_ready() --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 3413a0709..3393a34ff 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -161,7 +161,7 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OPERATION_TIMEOUTED; } - rc = Curl_select(conn->sock[sockindex], + rc = Curl_socket_ready(conn->sock[sockindex], conn->sock[sockindex], (int)timeout_ms); if(rc > 0) /* reabable or writable, go loop*/ @@ -535,7 +535,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(conn->ssl[sockindex].session) { while(!done) { - int what = Curl_select(conn->sock[sockindex], + int what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close -- cgit v1.2.1 From d58c7a8bdd6b54df30c7814c52847d32e2059172 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 27 Mar 2007 18:16:35 +0000 Subject: Update message --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 3393a34ff..3def5d998 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -173,7 +173,7 @@ static CURLcode handshake(struct connectdata *conn, } else { /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", SOCKERRNO); + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } } @@ -566,7 +566,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) } else { /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", SOCKERRNO); + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); retval = -1; done = 1; } -- cgit v1.2.1 From cea9695bcfd157926670db57ba2495e1e3940730 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 21 Apr 2007 21:32:31 +0000 Subject: Daniel Black filed bug #1704675 (http://curl.haxx.se/bug/view.cgi?id=1704675) identifying a double-free problem in the SSL-dealing layer, telling GnuTLS to free NULL credentials on closedown after a failure and a bad #ifdef for NSS when closing down SSL. --- lib/gtls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 3def5d998..73461b9cc 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -502,7 +502,8 @@ static void close_one(struct connectdata *conn, gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); gnutls_deinit(conn->ssl[index].session); } - gnutls_certificate_free_credentials(conn->ssl[index].cred); + if(conn->ssl[index].cred) + gnutls_certificate_free_credentials(conn->ssl[index].cred); } void Curl_gtls_close(struct connectdata *conn) -- cgit v1.2.1 From 503557e5ceac4ec3e5caec1d0a2e4d2f39eca471 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 28 Apr 2007 21:01:30 +0000 Subject: Peter O'Gorman fixed libcurl to not init GnuTLS as early as we did before, since it then inits libgcrypt and libgcrypt is being evil and EXITS the application if it fails to get a fine random seed. That's really not a nice thing to do by a library. --- lib/gtls.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 73461b9cc..0e100c621 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -63,7 +63,7 @@ static void tls_log_func(int level, const char *str) fprintf(stderr, "|<%d>| %s", level, str); } #endif - +static bool gtls_inited = FALSE; /* * Custom push and pull callback functions used by GNU TLS to read and write * to the socket. These functions are simple wrappers to send() and recv() @@ -85,17 +85,33 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) /* Global GnuTLS init, called from Curl_ssl_init() */ int Curl_gtls_init(void) { - gnutls_global_init(); +/* Unfortunately we can not init here, things like curl --version will + * fail to work if there is no egd socket available because libgcrypt + * will EXIT the application!! + * By doing the actual init later (before actually trying to use GnuTLS), + * we can at least provide basic info etc. + */ + return 1; +} + +static int _Curl_gtls_init(void) +{ + int ret = 1; + if (!gtls_inited) { + ret = gnutls_global_init()?0:1; #ifdef GTLSDEBUG - gnutls_global_set_log_function(tls_log_func); - gnutls_global_set_log_level(2); + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(2); #endif - return 1; + gtls_inited = TRUE; + } + return ret; } int Curl_gtls_cleanup(void) { - gnutls_global_deinit(); + if (gtls_inited) + gnutls_global_deinit(); return 1; } @@ -132,7 +148,8 @@ static CURLcode handshake(struct connectdata *conn, { struct SessionHandle *data = conn->data; int rc; - + if (!gtls_inited) + _Curl_gtls_init(); do { rc = gnutls_handshake(session); @@ -227,6 +244,7 @@ Curl_gtls_connect(struct connectdata *conn, void *ssl_sessionid; size_t ssl_idsize; + if (!gtls_inited) _Curl_gtls_init(); /* GnuTLS only supports TLSv1 (and SSLv3?) */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); -- cgit v1.2.1 From 4b1782c37141b82aa118eaf05061bb9ba1759700 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 10 Jul 2007 21:36:30 +0000 Subject: 7.16.4 preps --- lib/gtls.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 0e100c621..a84128e3e 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -420,6 +420,43 @@ Curl_gtls_connect(struct connectdata *conn, else infof(data, "\t common name: %s (matched)\n", certbuf); + /* Check for time-based validity */ + clock = gnutls_x509_crt_get_expiration_time(x509_cert); + + if(clock == (time_t)-1) { + failf(data, "server cert expiration date verify failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(clock < time(NULL)) { + if (data->set.ssl.verifypeer) { + failf(data, "server certificate expiration date has passed."); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t server certificate expiration date FAILED\n"); + } + else + infof(data, "\t server certificate expiration date OK\n"); + + clock = gnutls_x509_crt_get_activation_time(x509_cert); + + if(clock == (time_t)-1) { + failf(data, "server cert activation date verify failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(clock > time(NULL)) { + if (data->set.ssl.verifypeer) { + failf(data, "server certificate not activated yet."); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t server certificate activation date FAILED\n"); + } + else + infof(data, "\t server certificate activation date OK\n"); + /* Show: - ciphers used -- cgit v1.2.1 From 4a2f0fb2beb95b2edccead115a92971643bd5297 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 20 Jul 2007 00:41:12 +0000 Subject: Made some const arrays static to avoid unnecessary stack usage. --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a84128e3e..23c2a28b4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -227,7 +227,7 @@ Curl_gtls_connect(struct connectdata *conn, int sockindex) { - const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; struct SessionHandle *data = conn->data; gnutls_session session; int rc; -- cgit v1.2.1 From f1fa7b8ba469d9b8681e30f107b44004695b32e9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 29 Jul 2007 12:54:05 +0000 Subject: Bug report #1759542 (http://curl.haxx.se/bug/view.cgi?id=1759542). A bad use of a socket after it has been closed, when the FTP-SSL data connection is taken down. --- lib/gtls.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 23c2a28b4..03572d88e 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -556,17 +556,17 @@ static void close_one(struct connectdata *conn, if(conn->ssl[index].session) { gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); gnutls_deinit(conn->ssl[index].session); + conn->ssl[index].session = NULL; } - if(conn->ssl[index].cred) + if(conn->ssl[index].cred) { gnutls_certificate_free_credentials(conn->ssl[index].cred); + conn->ssl[index].cred = NULL; + } } -void Curl_gtls_close(struct connectdata *conn) +void Curl_gtls_close(struct connectdata *conn, int sockindex) { - if(conn->ssl[0].use) - close_one(conn, 0); - if(conn->ssl[1].use) - close_one(conn, 1); + close_one(conn, sockindex); } /* @@ -631,8 +631,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) } gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); + conn->ssl[sockindex].cred = NULL; conn->ssl[sockindex].session = NULL; - conn->ssl[sockindex].use = FALSE; return retval; } -- cgit v1.2.1 From 50c10aa5bf545eedfdbe561116656b6ec12654cd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Aug 2007 21:20:01 +0000 Subject: Patrick Monnerat and I modified libcurl so that now it *copies* all strings passed to it with curl_easy_setopt()! Previously it has always just refered to the data, forcing the user to keep the data around until libcurl is done with it. That is now history and libcurl will instead clone the given strings and keep private copies. --- lib/gtls.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 03572d88e..a40ea096b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -299,11 +299,13 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) return CURLE_SSL_CONNECT_ERROR; - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, data->set.cert, - data->set.key != 0 ? data->set.key : data->set.cert, - do_file_type(data->set.cert_type) ) ) { + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ) ) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } -- cgit v1.2.1 From d994fcf2b1b22cf08073cec98b8deb7031758197 Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Fri, 24 Aug 2007 09:06:17 +0000 Subject: Remove leading space in curl_version_info ss_version field. --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a40ea096b..834994069 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -691,7 +691,7 @@ void Curl_gtls_session_free(void *ptr) size_t Curl_gtls_version(char *buffer, size_t size) { - return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL)); + return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } #endif /* USE_GNUTLS */ -- cgit v1.2.1 From 9f44a95522162c0f4a61093efe1bf1f58b087358 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Thu, 30 Aug 2007 20:34:57 +0000 Subject: Renamed several libcurl error codes and options to make them more general and allow reuse by multiple protocols. Several unused error codes were removed. In all cases, macros were added to preserve source (and binary) compatibility with the old names. These macros are subject to removal at a future date, but probably not before 2009. An application can be tested to see if it is using any obsolete code by compiling it with the CURL_NO_OLDIES macro defined. Documented some newer error codes in libcurl-error(3) --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 834994069..8d126d005 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -175,7 +175,7 @@ static CURLcode handshake(struct connectdata *conn, if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEOUTED; + return CURLE_OPERATION_TIMEDOUT; } rc = Curl_socket_ready(conn->sock[sockindex], -- cgit v1.2.1 From ce81cd21d3865270867d68935c9700dbaf5b5fcc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 3 Oct 2007 08:07:50 +0000 Subject: I renamed the CURLE_SSL_PEER_CERTIFICATE error code to CURLE_PEER_FAILED_VERIFICATION (standard CURL_NO_OLDIES style), and made this return code get used by the previous SSH MD5 fingerprint check in case it fails. --- lib/gtls.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 8d126d005..2aeb093d0 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -352,7 +352,7 @@ Curl_gtls_connect(struct connectdata *conn, if(!chainp) { if(data->set.ssl.verifyhost) { failf(data, "failed to get server cert"); - return CURLE_SSL_PEER_CERTIFICATE; + return CURLE_PEER_FAILED_VERIFICATION; } infof(data, "\t common name: WARNING couldn't obtain\n"); } @@ -413,7 +413,7 @@ Curl_gtls_connect(struct connectdata *conn, failf(data, "SSL: certificate subject name (%s) does not match " "target host name '%s'", certbuf, conn->host.dispname); gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_PEER_CERTIFICATE; + return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", @@ -433,7 +433,7 @@ Curl_gtls_connect(struct connectdata *conn, if(clock < time(NULL)) { if (data->set.ssl.verifypeer) { failf(data, "server certificate expiration date has passed."); - return CURLE_SSL_PEER_CERTIFICATE; + return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate expiration date FAILED\n"); @@ -451,7 +451,7 @@ Curl_gtls_connect(struct connectdata *conn, if(clock > time(NULL)) { if (data->set.ssl.verifypeer) { failf(data, "server certificate not activated yet."); - return CURLE_SSL_PEER_CERTIFICATE; + return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate activation date FAILED\n"); -- cgit v1.2.1 From cbd1a77ec24e397d05f20c6de106625676343c9d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 7 Nov 2007 09:21:35 +0000 Subject: if () => if() while () => while() and some other minor re-indentings --- lib/gtls.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 2aeb093d0..49b0fc739 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -97,7 +97,7 @@ int Curl_gtls_init(void) static int _Curl_gtls_init(void) { int ret = 1; - if (!gtls_inited) { + if(!gtls_inited) { ret = gnutls_global_init()?0:1; #ifdef GTLSDEBUG gnutls_global_set_log_function(tls_log_func); @@ -110,7 +110,7 @@ static int _Curl_gtls_init(void) int Curl_gtls_cleanup(void) { - if (gtls_inited) + if(gtls_inited) gnutls_global_deinit(); return 1; } @@ -148,7 +148,7 @@ static CURLcode handshake(struct connectdata *conn, { struct SessionHandle *data = conn->data; int rc; - if (!gtls_inited) + if(!gtls_inited) _Curl_gtls_init(); do { rc = gnutls_handshake(session); @@ -198,7 +198,7 @@ static CURLcode handshake(struct connectdata *conn, break; } while(1); - if (rc < 0) { + if(rc < 0) { failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } @@ -244,7 +244,7 @@ Curl_gtls_connect(struct connectdata *conn, void *ssl_sessionid; size_t ssl_idsize; - if (!gtls_inited) _Curl_gtls_init(); + if(!gtls_inited) _Curl_gtls_init(); /* GnuTLS only supports TLSv1 (and SSLv3?) */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); @@ -269,7 +269,7 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); - if (data->set.ssl.verifypeer) + if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } else @@ -365,14 +365,14 @@ Curl_gtls_connect(struct connectdata *conn, gnutls_certificate_set_verify_limits(). */ rc = gnutls_certificate_verify_peers2(session, &verify_status); - if (rc < 0) { + if(rc < 0) { failf(data, "server cert verify failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { - if (data->set.ssl.verifypeer) { + if(data->set.ssl.verifypeer) { failf(data, "server certificate verification failed. CAfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); return CURLE_SSL_CACERT; @@ -409,7 +409,7 @@ Curl_gtls_connect(struct connectdata *conn, rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); if(!rc) { - if (data->set.ssl.verifyhost > 1) { + if(data->set.ssl.verifyhost > 1) { failf(data, "SSL: certificate subject name (%s) does not match " "target host name '%s'", certbuf, conn->host.dispname); gnutls_x509_crt_deinit(x509_cert); @@ -431,7 +431,7 @@ Curl_gtls_connect(struct connectdata *conn, } if(clock < time(NULL)) { - if (data->set.ssl.verifypeer) { + if(data->set.ssl.verifypeer) { failf(data, "server certificate expiration date has passed."); return CURLE_PEER_FAILED_VERIFICATION; } @@ -449,7 +449,7 @@ Curl_gtls_connect(struct connectdata *conn, } if(clock > time(NULL)) { - if (data->set.ssl.verifypeer) { + if(data->set.ssl.verifypeer) { failf(data, "server certificate not activated yet."); return CURLE_PEER_FAILED_VERIFICATION; } @@ -670,12 +670,12 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ } *wouldblock = FALSE; - if (!ret) { + if(!ret) { failf(conn->data, "Peer closed the TLS connection"); return -1; } - if (ret < 0) { + if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", (int)ret, gnutls_strerror(ret)); return -1; -- cgit v1.2.1 From 1b701c746f66b8fd5bf3017c36254dbde8456df2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 7 Feb 2008 22:25:04 +0000 Subject: - Refactored a lot of timeout code into a few functions in an attempt to make them all use the same (hopefully correct) logic to make it less error-prone and easier to introduce library-wide where it should be used. --- lib/gtls.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 49b0fc739..d317d2bb0 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -154,23 +154,7 @@ static CURLcode handshake(struct connectdata *conn, rc = gnutls_handshake(session); if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - long timeout_ms = DEFAULT_CONNECT_TIMEOUT; - long has_passed; - - if(duringconnect && data->set.connecttimeout) - timeout_ms = data->set.connecttimeout; - - if(data->set.timeout) { - /* get the strictest timeout of the ones converted to milliseconds */ - if(data->set.timeout < timeout_ms) - timeout_ms = data->set.timeout; - } - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - - /* subtract the passed time */ - timeout_ms -= has_passed; + long timeout_ms = Curl_connecttimeleft(conn, NULL, duringconnect); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ -- cgit v1.2.1 From 4c841a1f0cf53d363d2ba3351c558ce8b06e9c25 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 8 Feb 2008 22:02:00 +0000 Subject: - Mike Hommey filed and fixed bug report #1889856 (http://curl.haxx.se/bug/view.cgi?id=1889856): When using the gnutls ssl layer, cleaning-up and reinitializing curl ends up with https requests failing with "ASN1 parser: Element was not found" errors. Obviously a regression added in 7.16.3. --- lib/gtls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index d317d2bb0..01ea303bb 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -110,8 +110,10 @@ static int _Curl_gtls_init(void) int Curl_gtls_cleanup(void) { - if(gtls_inited) + if(gtls_inited) { gnutls_global_deinit(); + gtls_inited = FALSE; + } return 1; } -- cgit v1.2.1 From e78652d850025d3a6ba53cf2e0c6434f7fc0a0a2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 15 Feb 2008 22:37:00 +0000 Subject: - Made the gnutls code path not even try to get the server cert if no peer verification is requested. Previously it would even return failure if gnutls failed to get the server cert even though no verification was asked for. - Fix my Curl_timeleft() leftover mistake in the gnutls code --- lib/gtls.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 01ea303bb..4152ded26 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -156,7 +156,7 @@ static CURLcode handshake(struct connectdata *conn, rc = gnutls_handshake(session); if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - long timeout_ms = Curl_connecttimeleft(conn, NULL, duringconnect); + long timeout_ms = Curl_timeleft(conn, NULL, duringconnect); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ @@ -336,38 +336,42 @@ Curl_gtls_connect(struct connectdata *conn, chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { - if(data->set.ssl.verifyhost) { + if(data->set.ssl.verifypeer) { failf(data, "failed to get server cert"); return CURLE_PEER_FAILED_VERIFICATION; } infof(data, "\t common name: WARNING couldn't obtain\n"); } - /* This function will try to verify the peer's certificate and return its - status (trusted, invalid etc.). The value of status should be one or more - of the gnutls_certificate_status_t enumerated elements bitwise or'd. To - avoid denial of service attacks some default upper limits regarding the - certificate key size and chain size are set. To override them use - gnutls_certificate_set_verify_limits(). */ + if(data->set.ssl.verifypeer) { + /* This function will try to verify the peer's certificate and return its + status (trusted, invalid etc.). The value of status should be one or + more of the gnutls_certificate_status_t enumerated elements bitwise + or'd. To avoid denial of service attacks some default upper limits + regarding the certificate key size and chain size are set. To override + them use gnutls_certificate_set_verify_limits(). */ - rc = gnutls_certificate_verify_peers2(session, &verify_status); - if(rc < 0) { - failf(data, "server cert verify failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } + rc = gnutls_certificate_verify_peers2(session, &verify_status); + if(rc < 0) { + failf(data, "server cert verify failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { - if(data->set.ssl.verifypeer) { - failf(data, "server certificate verification failed. CAfile: %s", - data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); - return CURLE_SSL_CACERT; + /* verify_status is a bitmask of gnutls_certificate_status bits */ + if(verify_status & GNUTLS_CERT_INVALID) { + if(data->set.ssl.verifypeer) { + failf(data, "server certificate verification failed. CAfile: %s", + data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); + return CURLE_SSL_CACERT; + } + else + infof(data, "\t server certificate verification FAILED\n"); } else - infof(data, "\t server certificate verification FAILED\n"); + infof(data, "\t server certificate verification OK\n"); } else - infof(data, "\t server certificate verification OK\n"); + infof(data, "\t server certificate verification SKIPPED\n"); /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); -- cgit v1.2.1 From f7b71c2abeedfc62d398491ec57a133527e6a752 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 16 Feb 2008 13:41:55 +0000 Subject: fix warnings about shadowing --- lib/gtls.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 4152ded26..c7c38642f 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -225,7 +225,7 @@ Curl_gtls_connect(struct connectdata *conn, size_t size; unsigned int algo; unsigned int bits; - time_t clock; + time_t certclock; const char *ptr; void *ssl_sessionid; size_t ssl_idsize; @@ -344,6 +344,10 @@ Curl_gtls_connect(struct connectdata *conn, } if(data->set.ssl.verifypeer) { + + gnutls_certificate_set_verify_limits(conn->ssl[sockindex].cred, + 40200, 38); + /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise @@ -413,14 +417,14 @@ Curl_gtls_connect(struct connectdata *conn, infof(data, "\t common name: %s (matched)\n", certbuf); /* Check for time-based validity */ - clock = gnutls_x509_crt_get_expiration_time(x509_cert); + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - if(clock == (time_t)-1) { + if(certclock == (time_t)-1) { failf(data, "server cert expiration date verify failed"); return CURLE_SSL_CONNECT_ERROR; } - if(clock < time(NULL)) { + if(certclock < time(NULL)) { if(data->set.ssl.verifypeer) { failf(data, "server certificate expiration date has passed."); return CURLE_PEER_FAILED_VERIFICATION; @@ -431,14 +435,14 @@ Curl_gtls_connect(struct connectdata *conn, else infof(data, "\t server certificate expiration date OK\n"); - clock = gnutls_x509_crt_get_activation_time(x509_cert); + certclock = gnutls_x509_crt_get_activation_time(x509_cert); - if(clock == (time_t)-1) { + if(certclock == (time_t)-1) { failf(data, "server cert activation date verify failed"); return CURLE_SSL_CONNECT_ERROR; } - if(clock > time(NULL)) { + if(certclock > time(NULL)) { if(data->set.ssl.verifypeer) { failf(data, "server certificate not activated yet."); return CURLE_PEER_FAILED_VERIFICATION; @@ -474,11 +478,11 @@ Curl_gtls_connect(struct connectdata *conn, gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); infof(data, "\t subject: %s\n", certbuf); - clock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", clock); + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", certclock); - clock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", clock); + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", certclock); size = sizeof(certbuf); gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); @@ -543,16 +547,16 @@ void Curl_gtls_close_all(struct SessionHandle *data) } static void close_one(struct connectdata *conn, - int index) + int idx) { - if(conn->ssl[index].session) { - gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[index].session); - conn->ssl[index].session = NULL; + if(conn->ssl[idx].session) { + gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->ssl[idx].session); + conn->ssl[idx].session = NULL; } - if(conn->ssl[index].cred) { - gnutls_certificate_free_credentials(conn->ssl[index].cred); - conn->ssl[index].cred = NULL; + if(conn->ssl[idx].cred) { + gnutls_certificate_free_credentials(conn->ssl[idx].cred); + conn->ssl[idx].cred = NULL; } } -- cgit v1.2.1 From 550d6f74b9223231d939ef8526090a3f387b0609 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 16 Feb 2008 13:44:23 +0000 Subject: oops, that was debug code not meant to be committed like this... --- lib/gtls.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index c7c38642f..e980a5bdc 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -344,10 +344,6 @@ Curl_gtls_connect(struct connectdata *conn, } if(data->set.ssl.verifypeer) { - - gnutls_certificate_set_verify_limits(conn->ssl[sockindex].cred, - 40200, 38); - /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise -- cgit v1.2.1 From 55700cb01f4a01b8187f387e1655371e6fe0703a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Feb 2008 08:28:02 +0000 Subject: - We no longer support setting the CURLOPT_URL option from inside a callback such as the CURLOPT_SSL_CTX_FUNCTION one treat that as if it was a Location: following. The patch that introduced this feature was done for 7.11.0, but this code and functionality has been broken since about 7.15.4 (March 2006) with the introduction of non-blocking OpenSSL "connects". It was a hack to begin with and since it doesn't work and hasn't worked correctly for a long time and nobody has even noticed, I consider it a very suitable subject for plain removal. And so it was done. --- lib/gtls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index e980a5bdc..2364c2778 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -230,7 +230,9 @@ Curl_gtls_connect(struct connectdata *conn, void *ssl_sessionid; size_t ssl_idsize; - if(!gtls_inited) _Curl_gtls_init(); + if(!gtls_inited) + _Curl_gtls_init(); + /* GnuTLS only supports TLSv1 (and SSLv3?) */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); -- cgit v1.2.1 From 53a549000c3634f6b0a5ed262d5834c3145885d7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Feb 2008 09:56:26 +0000 Subject: - Based on initial work done by Gautam Kachroo to address a bug, we now keep better control at the exact state of the connection's SSL status so that we know exactly when it has completed the SSL negotiation or not so that there won't be accidental re-uses of connections that are wrongly believed to be in SSL-completed-negotiate state. --- lib/gtls.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 2364c2778..3bf988194 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -501,6 +501,8 @@ Curl_gtls_connect(struct connectdata *conn, ptr = gnutls_mac_get_name(gnutls_mac_get(session)); infof(data, "\t MAC: %s\n", ptr); + connssl->state = ssl_connection_complete; + if(!ssl_sessionid) { /* this session was not previously in the cache, add it now */ -- cgit v1.2.1 From 9019fc5671f10dce9d29992d54a2b9ea5ac16b8b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Feb 2008 10:01:28 +0000 Subject: oops, fixed to build --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 3bf988194..05efd11c7 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -501,7 +501,7 @@ Curl_gtls_connect(struct connectdata *conn, ptr = gnutls_mac_get_name(gnutls_mac_get(session)); infof(data, "\t MAC: %s\n", ptr); - connssl->state = ssl_connection_complete; + conn->ssl[sockindex].state = ssl_connection_complete; if(!ssl_sessionid) { /* this session was not previously in the cache, add it now */ -- cgit v1.2.1 From 74241e7d852531bc8ee9301fd3e5ec0c5fabc7cf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Feb 2008 07:51:39 +0000 Subject: - Kaspar Brand made GnuTLS-built libcurl properly acknowledge the option that forces it to prefer SSLv3. --- lib/gtls.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 05efd11c7..01e8e97a4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -233,7 +233,7 @@ Curl_gtls_connect(struct connectdata *conn, if(!gtls_inited) _Curl_gtls_init(); - /* GnuTLS only supports TLSv1 (and SSLv3?) */ + /* GnuTLS only supports SSLv3 and TLSv1 */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; @@ -280,6 +280,13 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) return CURLE_SSL_CONNECT_ERROR; + if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { + int protocol_priority[] = { GNUTLS_SSL3, 0 }; + gnutls_protocol_set_priority(session, protocol_priority); + if(rc < 0) + return CURLE_SSL_CONNECT_ERROR; + } + /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ -- cgit v1.2.1 From 9682c2037e964cd64ba581ceff61a04bb6395a6b Mon Sep 17 00:00:00 2001 From: Gunter Knauf Date: Tue, 26 Feb 2008 10:30:13 +0000 Subject: Added support for server name indication (RFC 4366). Patch submitted by Kaspar Brand. --- lib/gtls.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 01e8e97a4..80100b4ed 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -43,6 +43,7 @@ #include "urldata.h" #include "sendf.h" +#include "inet_pton.h" #include "gtls.h" #include "sslgen.h" #include "parsedate.h" @@ -229,6 +230,11 @@ Curl_gtls_connect(struct connectdata *conn, const char *ptr; void *ssl_sessionid; size_t ssl_idsize; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif if(!gtls_inited) _Curl_gtls_init(); @@ -275,6 +281,15 @@ Curl_gtls_connect(struct connectdata *conn, /* convenient assign */ session = conn->ssl[sockindex].session; + if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && +#endif + (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, + strlen(conn->host.name)) < 0)) + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + /* Use default priorities */ rc = gnutls_set_default_priority(session); if(rc < 0) -- cgit v1.2.1 From 3fe8251dfbb533803e25cc38365114b28c5a1c85 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 6 Jun 2008 18:40:21 +0000 Subject: - Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for OpenSSL, NSS and GnuTLS-built libcurls. --- lib/gtls.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 80100b4ed..e9e410243 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -271,6 +271,21 @@ Curl_gtls_connect(struct connectdata *conn, rc, data->set.ssl.CAfile); } + if(data->set.ssl.CRLfile) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, + data->set.ssl.CRLfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)\n", + data->set.ssl.CRLfile, gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s\n", + rc, data->set.ssl.CRLfile); + } + /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); if(rc) { -- cgit v1.2.1 From 621c2b901527248b4822895bc0305373a7d2dd63 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 6 Jun 2008 20:52:32 +0000 Subject: - Axel Tillequin and Arnaud Ebalard added support for CURLOPT_ISSUERCERT, for OpenSSL, NSS and GnuTLS-built libcurls. --- lib/gtls.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index e9e410243..6e762f161 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -143,6 +143,32 @@ static void showtime(struct SessionHandle *data, infof(data, "%s", data->state.buffer); } +static gnutls_datum load_file (const char *file) +{ + FILE *f; + gnutls_datum loaded_file = { NULL, 0 }; + long filelen; + void *ptr; + + if (!(f = fopen(file, "r")) + || fseek(f, 0, SEEK_END) != 0 + || (filelen = ftell(f)) < 0 + || fseek(f, 0, SEEK_SET) != 0 + || !(ptr = malloc((size_t)filelen)) + || fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { + return loaded_file; + } + + loaded_file.data = ptr; + loaded_file.size = (unsigned int)filelen; + return loaded_file; +} + +static void unload_file(gnutls_datum data) { + free(data.data); +} + + /* this function does a BLOCKING SSL/TLS (re-)handshake */ static CURLcode handshake(struct connectdata *conn, gnutls_session session, @@ -221,7 +247,8 @@ Curl_gtls_connect(struct connectdata *conn, unsigned int cert_list_size; const gnutls_datum *chainp; unsigned int verify_status; - gnutls_x509_crt x509_cert; + gnutls_x509_crt x509_cert,x509_issuer; + gnutls_datum issuerp; char certbuf[256]; /* big enough? */ size_t size; unsigned int algo; @@ -375,7 +402,9 @@ Curl_gtls_connect(struct connectdata *conn, chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { - if(data->set.ssl.verifypeer) { + if(data->set.ssl.verifypeer || + data->set.ssl.verifyhost || + data->set.ssl.issuercert) { failf(data, "failed to get server cert"); return CURLE_PEER_FAILED_VERIFICATION; } @@ -399,8 +428,9 @@ Curl_gtls_connect(struct connectdata *conn, /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { if(data->set.ssl.verifypeer) { - failf(data, "server certificate verification failed. CAfile: %s", - data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); + failf(data, "server certificate verification failed. CAfile: %s " + "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", + data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); return CURLE_SSL_CACERT; } else @@ -419,6 +449,21 @@ Curl_gtls_connect(struct connectdata *conn, gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + if (data->set.ssl.issuercert) { + gnutls_x509_crt_init(&x509_issuer); + issuerp = load_file(data->set.ssl.issuercert); + gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer); + unload_file(issuerp); + if (rc <= 0) { + failf(data, "server certificate issuer check failed (IssuerCert: %s)", + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + return CURLE_SSL_ISSUER_ERROR; + } + infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n", + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + } + size=sizeof(certbuf); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ -- cgit v1.2.1 From 3940e69c91f8739b679309e870eae3e4e8af728f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 10 Jun 2008 21:53:59 +0000 Subject: fix warning in GnuTLS build by making sure Curl_gtls_send() takes a const void * --- lib/gtls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 6e762f161..89a8079bf 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -607,9 +607,9 @@ Curl_gtls_connect(struct connectdata *conn, /* return number of sent (non-SSL) bytes */ ssize_t Curl_gtls_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len) + int sockindex, + const void *mem, + size_t len) { ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); -- cgit v1.2.1 From a579d6706436615845f57692921e0891fb6e3719 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 15 Oct 2008 21:43:48 +0000 Subject: - Pascal Terjan filed bug #2154627 (http://curl.haxx.se/bug/view.cgi?id=2154627) which pointed out that libcurl uses strcasecmp() in multiple places where it causes failures when the Turkish locale is used. This is because 'i' and 'I' isn't the same letter so strcasecmp() on those letters are different in Turkish than in English (or just about all other languages). I thus introduced a totally new internal function in libcurl (called Curl_ascii_equal) for doing case insentive comparisons for english-(ascii?) style strings that thus will make "file" and "FILE" match even if the Turkish locale is selected. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 89a8079bf..17e3947c9 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -223,9 +223,9 @@ static gnutls_x509_crt_fmt do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(curl_strequal(type, "PEM")) + if(Curl_ascii_equal(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(curl_strequal(type, "DER")) + if(Curl_ascii_equal(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } -- cgit v1.2.1 From 9d16b4081ed011c11f9876ae2685076e92113593 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 Oct 2008 08:23:48 +0000 Subject: Renamed Curl_ascii_equal to Curl_raw_equal and bugfixed the my_toupper function used in strequal.c so now all test cases run fine for me again. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 17e3947c9..17f40ea7d 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -223,9 +223,9 @@ static gnutls_x509_crt_fmt do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(Curl_ascii_equal(type, "PEM")) + if(Curl_raw_equal(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(Curl_ascii_equal(type, "DER")) + if(Curl_raw_equal(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } -- cgit v1.2.1 From 4cbc0f6c2e9557e7aad07abd62e6b836f78134e1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 11 Nov 2008 22:19:27 +0000 Subject: - Rainer Canavan filed bug #2255627 (http://curl.haxx.se/bug/view.cgi?id=2255627) which pointed out that a program using libcurl's multi interface to download a HTTPS page with a libcurl built powered by OpenSSL, would easily get silly and instead hand over SSL details as data instead of the actual HTTP headers and body. This happened because libcurl would consider the connection handshake done too early. This problem was introduced at September 22nd 2008 with my fix of the bug #2107377 The correct fix is now instead done within the GnuTLS-handling code, as both the OpenSSL and the NSS code already deal with this situation in similar fashion. I added test case 560 in an attempt to verify this fix, but unfortunately it didn't trigger it even before this fix! --- lib/gtls.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 17f40ea7d..4a3232cc7 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -263,6 +263,11 @@ Curl_gtls_connect(struct connectdata *conn, struct in_addr addr; #endif + if(conn->ssl[sockindex].state == ssl_connection_complete) + /* to make us tolerant against being called more than once for the + same connection */ + return CURLE_OK; + if(!gtls_inited) _Curl_gtls_init(); -- cgit v1.2.1 From e5084c1eca5bca632e15ba1f8ed1e95163244588 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Tue, 18 Nov 2008 08:53:51 +0000 Subject: Added #include "rawstr.h" --- lib/gtls.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 4a3232cc7..1e054d16f 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -49,6 +49,8 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" +#include "rawstr.h" + #define _MPRINTF_REPLACE /* use our functions only */ #include #include "memory.h" -- cgit v1.2.1 From 9aac2328c6544ac794571759621cf262cd5d8a29 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Tue, 18 Nov 2008 09:11:34 +0000 Subject: Made an array static const --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 1e054d16f..53a7400a8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -345,7 +345,7 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { - int protocol_priority[] = { GNUTLS_SSL3, 0 }; + static const int protocol_priority[] = { GNUTLS_SSL3, 0 }; gnutls_protocol_set_priority(session, protocol_priority); if(rc < 0) return CURLE_SSL_CONNECT_ERROR; -- cgit v1.2.1 From 9a4c887c4a7279acc4cae66b11540746244e9cc3 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Thu, 12 Feb 2009 20:48:40 +0000 Subject: Added support for Digest and NTLM authentication using GnuTLS. --- lib/gtls.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 53a7400a8..b37edd45f 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -33,6 +33,7 @@ #ifdef USE_GNUTLS #include #include +#include #include #include @@ -777,4 +778,29 @@ size_t Curl_gtls_version(char *buffer, size_t size) return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } +static void gtls_seed(struct SessionHandle *data) +{ + /* TODO: to a good job seeding the RNG */ + /* This may involve the gcry_control function and these options: */ + /* GCRYCTL_SET_RANDOM_SEED_FILE */ + /* GCRYCTL_SET_RNDEGD_SOCKET */ +} + +int Curl_gtls_seed(struct SessionHandle *data) +{ + /* we have the "SSL is seeded" boolean static to prevent multiple + time-consuming seedings in vain */ + static bool ssl_seeded = FALSE; + + /* Quickly add a bit of entropy */ + gcry_fast_random_poll(); + + if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || + data->set.str[STRING_SSL_EGDSOCKET]) { + gtls_seed(data); + ssl_seeded = TRUE; + } + return 0; +} + #endif /* USE_GNUTLS */ -- cgit v1.2.1 From d207ea1652f4712c6e46e7c9c8ea6bdf29fd4be3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 25 Feb 2009 12:51:17 +0000 Subject: - As Daniel Fandrich figured out, we must do the GnuTLS initing in the curl_global_init() function to properly maintain the performing functions thread-safe. We've previously (28 April 2007) moved the init to a later time just to avoid it to fail very early when libgcrypt dislikes the situation, but that move was bad and the fix should rather be in libgcrypt or elsewhere. --- lib/gtls.c | 52 ++++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 30 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index b37edd45f..839d28bc2 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -86,19 +86,14 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) return sread(s, buf, len); } -/* Global GnuTLS init, called from Curl_ssl_init() */ -int Curl_gtls_init(void) -{ -/* Unfortunately we can not init here, things like curl --version will - * fail to work if there is no egd socket available because libgcrypt - * will EXIT the application!! - * By doing the actual init later (before actually trying to use GnuTLS), - * we can at least provide basic info etc. +/* Curl_gtls_init() + * + * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that + * are not thread-safe and thus this function itself is not thread-safe and + * must only be called from within curl_global_init() to keep the thread + * situation under control! */ - return 1; -} - -static int _Curl_gtls_init(void) +int Curl_gtls_init(void) { int ret = 1; if(!gtls_inited) { @@ -181,7 +176,7 @@ static CURLcode handshake(struct connectdata *conn, struct SessionHandle *data = conn->data; int rc; if(!gtls_inited) - _Curl_gtls_init(); + Curl_gtls_init(); do { rc = gnutls_handshake(session); @@ -272,7 +267,7 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_OK; if(!gtls_inited) - _Curl_gtls_init(); + Curl_gtls_init(); /* GnuTLS only supports SSLv3 and TLSv1 */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { @@ -309,8 +304,8 @@ Curl_gtls_connect(struct connectdata *conn, if(data->set.ssl.CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, - data->set.ssl.CRLfile, - GNUTLS_X509_FMT_PEM); + data->set.ssl.CRLfile, + GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)\n", data->set.ssl.CRLfile, gnutls_strerror(rc)); @@ -437,8 +432,8 @@ Curl_gtls_connect(struct connectdata *conn, if(verify_status & GNUTLS_CERT_INVALID) { if(data->set.ssl.verifypeer) { failf(data, "server certificate verification failed. CAfile: %s " - "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", - data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); + "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", + data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); return CURLE_SSL_CACERT; } else @@ -465,11 +460,11 @@ Curl_gtls_connect(struct connectdata *conn, unload_file(issuerp); if (rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); return CURLE_SSL_ISSUER_ERROR; } infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); } size=sizeof(certbuf); @@ -778,14 +773,6 @@ size_t Curl_gtls_version(char *buffer, size_t size) return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } -static void gtls_seed(struct SessionHandle *data) -{ - /* TODO: to a good job seeding the RNG */ - /* This may involve the gcry_control function and these options: */ - /* GCRYCTL_SET_RANDOM_SEED_FILE */ - /* GCRYCTL_SET_RNDEGD_SOCKET */ -} - int Curl_gtls_seed(struct SessionHandle *data) { /* we have the "SSL is seeded" boolean static to prevent multiple @@ -797,7 +784,12 @@ int Curl_gtls_seed(struct SessionHandle *data) if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || data->set.str[STRING_SSL_EGDSOCKET]) { - gtls_seed(data); + + /* TODO: to a good job seeding the RNG + This may involve the gcry_control function and these options: + GCRYCTL_SET_RANDOM_SEED_FILE + GCRYCTL_SET_RNDEGD_SOCKET + */ ssl_seeded = TRUE; } return 0; -- cgit v1.2.1 From 12bfcb501c82f7a0911a8ee92b5e8143225ce207 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 8 Mar 2009 22:52:05 +0000 Subject: - Andre Guibert de Bruet fixed the gnutls-using code: There are a few places in the gnutls code where we were checking for negative values for errors, when the man pages state that GNUTLS_E_SUCCESS is returned on success and other values indicate error conditions. --- lib/gtls.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 839d28bc2..8bf754b92 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -277,7 +277,7 @@ Curl_gtls_connect(struct connectdata *conn, /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); - if(rc < 0) { + if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } @@ -318,7 +318,7 @@ Curl_gtls_connect(struct connectdata *conn, /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); - if(rc) { + if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } @@ -337,13 +337,13 @@ Curl_gtls_connect(struct connectdata *conn, /* Use default priorities */ rc = gnutls_set_default_priority(session); - if(rc < 0) + if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { static const int protocol_priority[] = { GNUTLS_SSL3, 0 }; gnutls_protocol_set_priority(session, protocol_priority); - if(rc < 0) + if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; } @@ -351,7 +351,7 @@ Curl_gtls_connect(struct connectdata *conn, is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc < 0) + if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; if(data->set.str[STRING_CERT]) { @@ -360,7 +360,7 @@ Curl_gtls_connect(struct connectdata *conn, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ) ) { + do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } -- cgit v1.2.1 From 33a3753c3f41d546ebf3350685eb7201d25783f4 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 21 Apr 2009 11:46:16 +0000 Subject: libcurl's memory.h renamed to curl_memory.h --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 8bf754b92..70b1b2510 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -54,7 +54,7 @@ #define _MPRINTF_REPLACE /* use our functions only */ #include -#include "memory.h" +#include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" -- cgit v1.2.1 From 915dfb494ec0be89724e81af1b050c49d9d13cac Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 4 May 2009 22:20:09 +0000 Subject: - Inspired by Michael Smith's session id fix for OpenSSL, I did the corresponding fix in the GnuTLS code: make sure to store the new session id in case the re-used one is rejected. --- lib/gtls.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 70b1b2510..f07854245 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -588,20 +588,39 @@ Curl_gtls_connect(struct connectdata *conn, conn->ssl[sockindex].state = ssl_connection_complete; - if(!ssl_sessionid) { - /* this session was not previously in the cache, add it now */ + { + /* we always unconditionally get the session id here, as even if we + already got it from the cache and asked to use it in the connection, it + might've been rejected and then a new one is in use now and we need to + detect that. */ + void *connect_sessionid; + size_t connect_idsize; /* get the session ID data size */ - gnutls_session_get_data(session, NULL, &ssl_idsize); - ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */ + gnutls_session_get_data(session, NULL, &connect_idsize); + connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ - if(ssl_sessionid) { + if(connect_sessionid) { /* extract session ID to the allocated buffer */ - gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize); + gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + + if(ssl_sessionid && + ((connect_idsize != ssl_idsize) || + memcmp(connect_sessionid, ssl_sessionid, ssl_idsize))) + /* there was one before in the cache, but without the same size or + with different contents so delete the old one */ + Curl_ssl_delsessionid(conn, ssl_sessionid); + else if(ssl_sessionid) { + /* it was in the cache and its the same one now, just leave it */ + free(connect_sessionid); + return CURLE_OK; + } + /* store this session id */ - return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize); + return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); } + } return CURLE_OK; -- cgit v1.2.1 From b40b98952319422dccaa28346d0e9077236030f7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 5 May 2009 08:33:29 +0000 Subject: I simplified the SSL session id re-use code now to *always* ditch the previous one and store the current one, as it makes the code less complex and I'm not even sure I can check for the same session id using memcmp() like that. --- lib/gtls.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f07854245..002246a0c 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -604,18 +604,10 @@ Curl_gtls_connect(struct connectdata *conn, /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, connect_sessionid, &connect_idsize); - if(ssl_sessionid && - ((connect_idsize != ssl_idsize) || - memcmp(connect_sessionid, ssl_sessionid, ssl_idsize))) - /* there was one before in the cache, but without the same size or - with different contents so delete the old one */ + if(ssl_sessionid) + /* there was one before in the cache, so instead of risking that the + previous one was rejected, we just kill that and store the new */ Curl_ssl_delsessionid(conn, ssl_sessionid); - else if(ssl_sessionid) { - /* it was in the cache and its the same one now, just leave it */ - free(connect_sessionid); - return CURLE_OK; - } - /* store this session id */ return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); -- cgit v1.2.1 From 4c207a004cce51e0dcd11c42eda514bd1587e8b2 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 22 Jul 2009 09:48:32 +0000 Subject: - David Binderman found a memory and fd leak in lib/gtls.c:load_file() (https://bugzilla.novell.com/523919). When looking at the code, I found that also the ptr pointer can leak. --- lib/gtls.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 002246a0c..d5c8f1a79 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -148,17 +148,22 @@ static gnutls_datum load_file (const char *file) long filelen; void *ptr; - if (!(f = fopen(file, "r")) - || fseek(f, 0, SEEK_END) != 0 + if (!(f = fopen(file, "r"))) + return loaded_file; + if (fseek(f, 0, SEEK_END) != 0 || (filelen = ftell(f)) < 0 || fseek(f, 0, SEEK_SET) != 0 - || !(ptr = malloc((size_t)filelen)) - || fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { - return loaded_file; + || !(ptr = malloc((size_t)filelen))) + goto out; + if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { + free(ptr); + goto out; } loaded_file.data = ptr; loaded_file.size = (unsigned int)filelen; +out: + fclose(f); return loaded_file; } -- cgit v1.2.1 From 6d891d2a3b907f12e5c9b335a806fcb7e77b877b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 1 Aug 2009 22:11:58 +0000 Subject: - Curt Bogmine reported a problem with SNI enabled on a particular server. We should introduce an option to disable SNI, but as we're in feature freeze now I've addressed the obvious bug here (pointed out by Peter Sylvester): we shouldn't try to enable SNI when SSLv2 or SSLv3 is explicitly selected. Code for OpenSSL and GnuTLS was fixed. NSS doesn't seem to have a particular option for SNI, or are we simply not using it? --- lib/gtls.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index d5c8f1a79..81748306e 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -260,6 +260,7 @@ Curl_gtls_connect(struct connectdata *conn, const char *ptr; void *ssl_sessionid; size_t ssl_idsize; + bool sni = TRUE; /* default is SNI enabled */ #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -279,6 +280,8 @@ Curl_gtls_connect(struct connectdata *conn, failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } + else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); @@ -335,6 +338,7 @@ Curl_gtls_connect(struct connectdata *conn, #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif + sni && (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, strlen(conn->host.name)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " -- cgit v1.2.1 From e7f81d59b085c141f64fb14b6a7c60493929e951 Mon Sep 17 00:00:00 2001 From: Gunter Knauf Date: Sun, 30 Aug 2009 01:36:01 +0000 Subject: add casts to silent compiler warnings with 64bit systems. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 81748306e..bfa4347bf 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -676,7 +676,7 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex) */ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { - int result; + ssize_t result; int retval = 0; struct SessionHandle *data = conn->data; int done = 0; @@ -776,7 +776,7 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", - (int)ret, gnutls_strerror(ret)); + (int)ret, gnutls_strerror((int)ret)); return -1; } -- cgit v1.2.1 From 3da1ade4e505837fefb0cb8003ce7c63c34d1f87 Mon Sep 17 00:00:00 2001 From: Gunter Knauf Date: Mon, 19 Oct 2009 18:10:47 +0000 Subject: added cast macros to silent compiler warnings with 64-bit systems. --- lib/gtls.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index bfa4347bf..797d18b16 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -58,6 +58,17 @@ /* The last #include file should be: */ #include "memdebug.h" +/* + Some hackish cast macros based on: + http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html +*/ +#ifndef GNUTLS_POINTER_TO_INT_CAST +#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) +#endif +#ifndef GNUTLS_INT_TO_POINTER_CAST +#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i)) +#endif + /* Enable GnuTLS debugging by defining GTLSDEBUG */ /*#define GTLSDEBUG */ @@ -78,12 +89,12 @@ static bool gtls_inited = FALSE; */ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { - return swrite(s, buf, len); + return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); } static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { - return sread(s, buf, len); + return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); } /* Curl_gtls_init() @@ -381,7 +392,7 @@ Curl_gtls_connect(struct connectdata *conn, /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, - (gnutls_transport_ptr)conn->sock[sockindex]); + GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); /* register callback functions to send and receive data. */ gnutls_transport_set_push_function(session, Curl_gtls_push); -- cgit v1.2.1 From 2309b4e330b96bc2e1f8e36b6184015e59544037 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Mar 2010 11:02:54 +0100 Subject: remove the CVSish $Id$ lines --- lib/gtls.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 797d18b16..079c6b1b0 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -18,7 +18,6 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - * $Id$ ***************************************************************************/ /* -- cgit v1.2.1 From ff8711135e9311d5a54c7210a5a87a86077271cb Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Sun, 4 Apr 2010 23:37:18 +0200 Subject: refactorize interface of Curl_ssl_recv/Curl_ssl_send --- lib/gtls.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 079c6b1b0..b7fa3c926 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -638,18 +638,21 @@ Curl_gtls_connect(struct connectdata *conn, } -/* return number of sent (non-SSL) bytes */ +/* for documentation see Curl_ssl_send() in sslgen.h */ ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, const void *mem, - size_t len) + size_t len, + int *curlcode) { ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); if(rc < 0 ) { - if(rc == GNUTLS_E_AGAIN) - return 0; /* EWOULDBLOCK equivalent */ - rc = -1; /* generic error code for send failure */ + *curlcode = (rc == GNUTLS_E_AGAIN) + ? /* EWOULDBLOCK */ -1 + : CURLE_SEND_ERROR; + + rc = -1; } return rc; @@ -748,22 +751,18 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) return retval; } -/* - * If the read would block we return -1 and set 'wouldblock' to TRUE. - * Otherwise we return the amount of data read. Other errors should return -1 - * and set 'wouldblock' to FALSE. - */ +/* for documentation see Curl_ssl_recv() in sslgen.h */ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ - bool *wouldblock) + int *curlcode) { ssize_t ret; ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *wouldblock = TRUE; + *curlcode = -1; return -1; } @@ -773,20 +772,22 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE); if(rc) /* handshake() writes error message on its own */ - return rc; - *wouldblock = TRUE; /* then return as if this was a wouldblock */ + *curlcode = rc; + else + *curlcode = -1; /* then return as if this was a wouldblock */ return -1; } - *wouldblock = FALSE; if(!ret) { failf(conn->data, "Peer closed the TLS connection"); + *curlcode = CURLE_RECV_ERROR; return -1; } if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", (int)ret, gnutls_strerror((int)ret)); + *curlcode = CURLE_RECV_ERROR; return -1; } -- cgit v1.2.1 From 2056ca9fea49558d5967a045955ade01cbcccad9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 16 Apr 2010 15:29:25 +0200 Subject: SSL_RECV: EOF is not an error here The recent overhaul of the SSL recv function made this treat a zero returned from gnutls_record_recv() as an error, and this caused our HTTPS test cases to fail. We leave it to upper layer code to detect if an EOF is a problem or not. --- lib/gtls.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index b7fa3c926..92d780530 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -778,12 +778,6 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ return -1; } - if(!ret) { - failf(conn->data, "Peer closed the TLS connection"); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", (int)ret, gnutls_strerror((int)ret)); -- cgit v1.2.1 From c2888604d7ead19473b5621f8f2edab60fc418de Mon Sep 17 00:00:00 2001 From: Jerome Vouillon Date: Fri, 16 Apr 2010 22:43:01 +0200 Subject: GnuTLS: make the connection phase non-blocking When multi interface is used, the SSL handshake is no longer blocking when GnuTLS is used. --- lib/gtls.c | 212 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 152 insertions(+), 60 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 92d780530..4f5edaf78 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -182,54 +182,76 @@ static void unload_file(gnutls_datum data) { } -/* this function does a BLOCKING SSL/TLS (re-)handshake */ +/* this function does a SSL/TLS (re-)handshake */ static CURLcode handshake(struct connectdata *conn, - gnutls_session session, int sockindex, - bool duringconnect) + bool duringconnect, + bool nonblocking) { struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + gnutls_session session = conn->ssl[sockindex].session; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; int rc; - if(!gtls_inited) - Curl_gtls_init(); - do { - rc = gnutls_handshake(session); + int what; - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - long timeout_ms = Curl_timeleft(conn, NULL, duringconnect); + while(1) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(conn, NULL, duringconnect); - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } - rc = Curl_socket_ready(conn->sock[sockindex], - conn->sock[sockindex], (int)timeout_ms); - if(rc > 0) - /* reabable or writable, go loop*/ - continue; - else if(0 == rc) { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - else { - /* anything that gets here is fatally bad */ + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, + nonblocking?0:(int)timeout_ms); + if(what < 0) { + /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } + else if(0 == what) { + if(nonblocking) { + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ } - else - break; - } while(1); - if(rc < 0) { - failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } + rc = gnutls_handshake(session); - return CURLE_OK; + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + connssl->connecting_state = + gnutls_record_get_direction(session)? + ssl_connect_2_writing:ssl_connect_2_reading; + if(nonblocking) { + return CURLE_OK; + } + } else if (rc < 0) { + failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); + } else { + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; + } + } } static gnutls_x509_crt_fmt do_file_type(const char *type) @@ -243,31 +265,14 @@ static gnutls_x509_crt_fmt do_file_type(const char *type) return -1; } - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic. - */ -CURLcode -Curl_gtls_connect(struct connectdata *conn, - int sockindex) - +static CURLcode +gtls_connect_step1(struct connectdata *conn, + int sockindex) { static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; struct SessionHandle *data = conn->data; gnutls_session session; int rc; - unsigned int cert_list_size; - const gnutls_datum *chainp; - unsigned int verify_status; - gnutls_x509_crt x509_cert,x509_issuer; - gnutls_datum issuerp; - char certbuf[256]; /* big enough? */ - size_t size; - unsigned int algo; - unsigned int bits; - time_t certclock; - const char *ptr; void *ssl_sessionid; size_t ssl_idsize; bool sni = TRUE; /* default is SNI enabled */ @@ -411,10 +416,29 @@ Curl_gtls_connect(struct connectdata *conn, infof (data, "SSL re-using session ID\n"); } - rc = handshake(conn, session, sockindex, TRUE); - if(rc) - /* handshake() sets its own error message with failf() */ - return rc; + return CURLE_OK; +} + +static CURLcode +gtls_connect_step3(struct connectdata *conn, + int sockindex) +{ + unsigned int cert_list_size; + const gnutls_datum *chainp; + unsigned int verify_status; + gnutls_x509_crt x509_cert,x509_issuer; + gnutls_datum issuerp; + char certbuf[256]; /* big enough? */ + size_t size; + unsigned int algo; + unsigned int bits; + time_t certclock; + const char *ptr; + struct SessionHandle *data = conn->data; + gnutls_session session = conn->ssl[sockindex].session; + int rc; + int incache; + void *ssl_sessionid; /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for @@ -623,20 +647,88 @@ Curl_gtls_connect(struct connectdata *conn, /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, connect_sessionid, &connect_idsize); - if(ssl_sessionid) + incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); + if (incache) { /* there was one before in the cache, so instead of risking that the previous one was rejected, we just kill that and store the new */ Curl_ssl_delsessionid(conn, ssl_sessionid); + } /* store this session id */ return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); } + } + + return CURLE_OK; +} + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic. + */ +/* We use connssl->connecting_state to keep track of the connection status; + there are three states: 'ssl_connect_1' (not started yet or complete), + 'ssl_connect_2_reading' (waiting for data from server), and + 'ssl_connect_2_writing' (waiting to be able to write). + */ +static CURLcode +gtls_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + int rc; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + /* Initiate the connection, if not already done */ + if(ssl_connect_1==connssl->connecting_state) { + rc = gtls_connect_step1 (conn, sockindex); + if(rc) + return rc; } + rc = handshake(conn, sockindex, TRUE, nonblocking); + if(rc) + /* handshake() sets its own error message with failf() */ + return rc; + + /* Finish connecting once the handshake is done */ + if(ssl_connect_1==connssl->connecting_state) { + rc = gtls_connect_step3(conn, sockindex); + if(rc) + return rc; + } + + *done = ssl_connect_1==connssl->connecting_state; + return CURLE_OK; } +CURLcode +Curl_gtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return gtls_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_gtls_connect(struct connectdata *conn, + int sockindex) + +{ + CURLcode retcode; + bool done = FALSE; + + retcode = gtls_connect_common(conn, sockindex, FALSE, &done); + if(retcode) + return retcode; + + DEBUGASSERT(done); + + return CURLE_OK; +} /* for documentation see Curl_ssl_send() in sslgen.h */ ssize_t Curl_gtls_send(struct connectdata *conn, @@ -769,7 +861,7 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ if(ret == GNUTLS_E_REHANDSHAKE) { /* BLOCKING call, this is bad but a work-around for now. Fixing this "the proper way" takes a whole lot of work. */ - CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE); + CURLcode rc = handshake(conn, num, FALSE, FALSE); if(rc) /* handshake() writes error message on its own */ *curlcode = rc; -- cgit v1.2.1 From d64bd82bdcb169d0647a80f00068cedd761f8163 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 7 May 2010 15:05:34 +0200 Subject: sendrecv: split the I/O handling into private handler Howard Chu brought the bulk work of this patch that properly moves out the sending and recving of data to the parts of the code that are properly responsible for the various ways of doing so. Daniel Stenberg assisted with polishing a few bits and fixed some minor flaws in the original patch. Another upside of this patch is that we now abuse CURLcodes less with the "magic" -1 return codes and instead use CURLE_AGAIN more consistently. --- lib/gtls.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 4f5edaf78..2cb1fae41 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -419,6 +419,9 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_OK; } +static Curl_recv gtls_recv; +static Curl_send gtls_send; + static CURLcode gtls_connect_step3(struct connectdata *conn, int sockindex) @@ -630,6 +633,8 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t MAC: %s\n", ptr); conn->ssl[sockindex].state = ssl_connection_complete; + conn->recv = gtls_recv; + conn->send = gtls_send; { /* we always unconditionally get the session id here, as even if we @@ -730,18 +735,17 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_OK; } -/* for documentation see Curl_ssl_send() in sslgen.h */ -ssize_t Curl_gtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - int *curlcode) +static ssize_t gtls_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) { ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); if(rc < 0 ) { *curlcode = (rc == GNUTLS_E_AGAIN) - ? /* EWOULDBLOCK */ -1 + ? CURLE_AGAIN : CURLE_SEND_ERROR; rc = -1; @@ -843,18 +847,17 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) return retval; } -/* for documentation see Curl_ssl_recv() in sslgen.h */ -ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - int *curlcode) +static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *curlcode) { ssize_t ret; ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *curlcode = -1; + *curlcode = CURLE_AGAIN; return -1; } @@ -866,7 +869,7 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ /* handshake() writes error message on its own */ *curlcode = rc; else - *curlcode = -1; /* then return as if this was a wouldblock */ + *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ return -1; } -- cgit v1.2.1 From bc8fc9803fbd0fa9daf0dba796d42d03faf49120 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 11 May 2010 22:48:38 +0200 Subject: sendrecv: make them two pairs of send/recv to properly deal with FTPS FTP(S) use two connections that can be set to different recv and send functions independently, so by introducing recv+send pairs in the same manner we already have sockets/connections we can work with FTPS fine. This commit fixes the FTPS regression introduced in change d64bd82. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 2cb1fae41..99be073a0 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -633,8 +633,8 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t MAC: %s\n", ptr); conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv = gtls_recv; - conn->send = gtls_send; + conn->recv[sockindex] = gtls_recv; + conn->send[sockindex] = gtls_send; { /* we always unconditionally get the session id here, as even if we -- cgit v1.2.1 From dc3e7df1c99c2ee9dae06453adbb94fe9584bf75 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 8 Nov 2010 04:03:11 +0100 Subject: fix compiler warning --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 99be073a0..fca2a7e7d 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -196,7 +196,7 @@ static CURLcode handshake(struct connectdata *conn, int rc; int what; - while(1) { + for(;;) { /* check allowed time left */ timeout_ms = Curl_timeleft(conn, NULL, duringconnect); -- cgit v1.2.1 From cbf4961bf3e42d88f6489f981efd509faa86f501 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Nov 2010 12:42:29 +0100 Subject: gnutls->handshake: improved timeout handling When no timeout is set, we call the socket_ready function with a timeout value of 0 during handshake, which makes it loop too much/fast in this function. It also made this function return CURLE_OPERATION_TIMEDOUT wrongly on a slow handshake. However, the particular bug report that highlighted this problem is not solved by this fix, as this fix only makes the more proper error get reported instead. Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=594150 Reported by: Johannes Ernst --- lib/gtls.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index fca2a7e7d..84410eda8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -216,19 +216,18 @@ static CURLcode handshake(struct connectdata *conn, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_ready(readfd, writefd, - nonblocking?0:(int)timeout_ms); + nonblocking?0:(int)timeout_ms?1000:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { - if(nonblocking) { + if(nonblocking) return CURLE_OK; - } - else { + else if(timeout_ms) { /* timeout */ - failf(data, "SSL connection timeout"); + failf(data, "SSL connection timeout at %ld", timeout_ms); return CURLE_OPERATION_TIMEDOUT; } } @@ -241,12 +240,14 @@ static CURLcode handshake(struct connectdata *conn, connssl->connecting_state = gnutls_record_get_direction(session)? ssl_connect_2_writing:ssl_connect_2_reading; - if(nonblocking) { + if(nonblocking) return CURLE_OK; - } - } else if (rc < 0) { + } + else if (rc < 0) { failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); - } else { + return CURLE_SSL_CONNECT_ERROR; + } + else { /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; -- cgit v1.2.1 From a83870ef9d1758de371551844efa4f17dda71581 Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Fri, 19 Nov 2010 13:31:34 -0800 Subject: Detect socket errors in GnuTLS on Windows On Windows, translate WSAGetLastError() to errno values as GNU TLS does it internally, too. This is necessary because send() and recv() on Windows don't set errno when they fail but GNU TLS expects a proper errno value. Bug: http://curl.haxx.se/bug/view.cgi?id=3110991 --- lib/gtls.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 84410eda8..93bb91de6 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -85,15 +85,52 @@ static bool gtls_inited = FALSE; * We use custom functions rather than the GNU TLS defaults because it allows * us to get specific about the fourth "flags" argument, and to use arbitrary * private data with gnutls_transport_set_ptr if we wish. + * + * On Windows translate WSAGetLastError() to errno values as GNU TLS does it + * internally too. This is necessary because send() and recv() on Windows + * don't set errno when they fail but GNU TLS expects a proper errno value. + * + * Use gnutls_transport_set_global_errno() like the GNU TLS documentation + * suggests to avoid problems with different errno variables when GNU TLS and + * curl are linked to different versions of msvcrt.dll. */ +#ifdef USE_WINSOCK +static void translate_wsa_to_errno(void) +{ + switch(WSAGetLastError()) { + case WSAEWOULDBLOCK: + gnutls_transport_set_global_errno(EAGAIN); + break; + case WSAEINTR: + gnutls_transport_set_global_errno(EINTR); + break; + default: + gnutls_transport_set_global_errno(EIO); + break; + } +} +#endif + static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { - return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); + ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); +#ifdef USE_WINSOCK + if(ret < 0) { + translate_wsa_to_errno(); + } +#endif + return ret; } static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { - return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); + ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); +#ifdef USE_WINSOCK + if(ret < 0) { + translate_wsa_to_errno(); + } +#endif + return ret; } /* Curl_gtls_init() -- cgit v1.2.1 From 13d537e40451c1c112b3c565ce0de7adfd8e41cc Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sat, 20 Nov 2010 05:00:12 +0100 Subject: gtls: define and use gtls_EAGAIN, gtls_EINTR and gtls_EIO. Winsock builds clobber some errno.h defines in setup_once. --- lib/gtls.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 93bb91de6..845dbbb12 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -78,6 +78,7 @@ static void tls_log_func(int level, const char *str) } #endif static bool gtls_inited = FALSE; + /* * Custom push and pull callback functions used by GNU TLS to read and write * to the socket. These functions are simple wrappers to send() and recv() @@ -86,28 +87,32 @@ static bool gtls_inited = FALSE; * us to get specific about the fourth "flags" argument, and to use arbitrary * private data with gnutls_transport_set_ptr if we wish. * - * On Windows translate WSAGetLastError() to errno values as GNU TLS does it - * internally too. This is necessary because send() and recv() on Windows - * don't set errno when they fail but GNU TLS expects a proper errno value. - * - * Use gnutls_transport_set_global_errno() like the GNU TLS documentation - * suggests to avoid problems with different errno variables when GNU TLS and - * curl are linked to different versions of msvcrt.dll. + * When these custom push and pull callbacks fail, GNU TLS checks its own + * session-specific error variable, and when not set also its own global + * errno variable, in order to take appropriate action. GNU TLS does not + * require that the transport is actually a socket. This implies that for + * Windows builds these callbacks should ideally set the session-specific + * error variable using function gnutls_transport_set_errno or as a last + * resort global errno variable using gnutls_transport_set_global_errno, + * with a transport agnostic error value. This implies that some winsock + * error translation must take place in these callbacks. */ + #ifdef USE_WINSOCK -static void translate_wsa_to_errno(void) +# define gtls_EINTR 4 +# define gtls_EIO 5 +# define gtls_EAGAIN 11 +static int gtls_mapped_sockerrno(void) { - switch(WSAGetLastError()) { + switch(SOCKERRNO) { case WSAEWOULDBLOCK: - gnutls_transport_set_global_errno(EAGAIN); - break; + return gtls_EAGAIN; case WSAEINTR: - gnutls_transport_set_global_errno(EINTR); - break; + return gtls_EINTR; default: - gnutls_transport_set_global_errno(EIO); break; } + return gtls_EIO; } #endif @@ -115,9 +120,8 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); #ifdef USE_WINSOCK - if(ret < 0) { - translate_wsa_to_errno(); - } + if(ret < 0) + gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif return ret; } @@ -126,9 +130,8 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); #ifdef USE_WINSOCK - if(ret < 0) { - translate_wsa_to_errno(); - } + if(ret < 0) + gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif return ret; } -- cgit v1.2.1 From adb49ad8bb280b586b387ba930c0681afee03923 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 4 Jan 2011 23:07:58 +0100 Subject: Curl_timeleft: s/conn/data in first argument As the function doesn't really use the connectdata struct but only the SessionHanadle struct I modified what argument it wants. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 845dbbb12..804f78446 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -238,7 +238,7 @@ static CURLcode handshake(struct connectdata *conn, for(;;) { /* check allowed time left */ - timeout_ms = Curl_timeleft(conn, NULL, duringconnect); + timeout_ms = Curl_timeleft(data, NULL, duringconnect); if(timeout_ms < 0) { /* no need to continue if time already is up */ -- cgit v1.2.1 From a9cd4f4ed49e1a0b79f8fc6a0cb129331fa04f23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 6 Jan 2011 00:47:37 +0100 Subject: gtls: fix memory leak Bug: http://curl.haxx.se/mail/lib-2011-01/0079.html Reported by: Quinn Slack --- lib/gtls.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 804f78446..9a87c39a8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -483,6 +483,7 @@ gtls_connect_step3(struct connectdata *conn, int rc; int incache; void *ssl_sessionid; + CURLcode result = CURLE_OK; /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for @@ -701,11 +702,17 @@ gtls_connect_step3(struct connectdata *conn, } /* store this session id */ - return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + if(result) { + free(connect_sessionid); + result = CURLE_OUT_OF_MEMORY; + } } + else + result = CURLE_OUT_OF_MEMORY; } - return CURLE_OK; + return result; } -- cgit v1.2.1 From 59cf93ccdbaa5e866f9de6b2d9b1ae5cee84863f Mon Sep 17 00:00:00 2001 From: Quinn Slack Date: Wed, 19 Jan 2011 20:35:02 +0100 Subject: TLS-SRP: support added when using GnuTLS --- lib/gtls.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 5 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 9a87c39a8..b5ef8fb99 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -346,6 +346,29 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + + rc = gnutls_srp_allocate_client_credentials( + &conn->ssl[sockindex].srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_allocate_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_TLSAUTH_FAILED; + } + + rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].srp_client_cred, + data->set.ssl.username, + data->set.ssl.password); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_set_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_TLSAUTH_FAILED; + } + } +#endif + if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, @@ -431,9 +454,18 @@ gtls_connect_step1(struct connectdata *conn, } } +#ifdef USE_TLS_SRP /* put the credentials to the current session */ - rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - conn->ssl[sockindex].cred); + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, + conn->ssl[sockindex].srp_client_cred); + if (rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + } + } else +#endif + rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + conn->ssl[sockindex].cred); /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, @@ -496,8 +528,21 @@ gtls_connect_step3(struct connectdata *conn, if(data->set.ssl.verifypeer || data->set.ssl.verifyhost || data->set.ssl.issuercert) { - failf(data, "failed to get server cert"); - return CURLE_PEER_FAILED_VERIFICATION; +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP + && data->set.ssl.username != NULL + && !data->set.ssl.verifypeer + && gnutls_cipher_get(session)) { + /* no peer cert, but auth is ok if we have SRP user and cipher and no + peer verify */ + } + else { +#endif + failf(data, "failed to get server cert"); + return CURLE_PEER_FAILED_VERIFICATION; +#ifdef USE_TLS_SRP + } +#endif } infof(data, "\t common name: WARNING couldn't obtain\n"); } @@ -530,8 +575,10 @@ gtls_connect_step3(struct connectdata *conn, else infof(data, "\t server certificate verification OK\n"); } - else + else { infof(data, "\t server certificate verification SKIPPED\n"); + goto after_server_cert_verification; + } /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); @@ -661,6 +708,8 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_deinit(x509_cert); +after_server_cert_verification: + /* compression algorithm (if any) */ ptr = gnutls_compression_get_name(gnutls_compression_get(session)); /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ @@ -820,6 +869,12 @@ static void close_one(struct connectdata *conn, gnutls_certificate_free_credentials(conn->ssl[idx].cred); conn->ssl[idx].cred = NULL; } +#ifdef USE_TLS_SRP + if (conn->ssl[idx].srp_client_cred) { + gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); + conn->ssl[idx].srp_client_cred = NULL; + } +#endif } void Curl_gtls_close(struct connectdata *conn, int sockindex) @@ -889,6 +944,12 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) } gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP + && data->set.ssl.username != NULL) + gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred); +#endif + conn->ssl[sockindex].cred = NULL; conn->ssl[sockindex].session = NULL; -- cgit v1.2.1 From 54d9f060b4b0a8fb5fa006813e4db1ca5c1a07e8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 7 Feb 2011 15:00:48 +0100 Subject: Curl_gmtime: added a portable gmtime Instead of polluting many places with #ifdefs, we create a single place for this function, and also check return code properly so that a NULL pointer returned won't cause problems. --- lib/gtls.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index b5ef8fb99..89174edf2 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -170,13 +170,12 @@ static void showtime(struct SessionHandle *data, const char *text, time_t stamp) { - struct tm *tm; -#ifdef HAVE_GMTIME_R struct tm buffer; - tm = (struct tm *)gmtime_r(&stamp, &buffer); -#else - tm = gmtime(&stamp); -#endif + const struct tm *tm = &buffer; + CURLcode result = Curl_gmtime(stamp, &buffer); + if(result) + return; + snprintf(data->state.buffer, BUFSIZE, "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", -- cgit v1.2.1 From 3cffcba3d0cf78a2aa17197059f810f5a7ce05a5 Mon Sep 17 00:00:00 2001 From: Quinn Slack Date: Wed, 9 Feb 2011 23:34:30 +0100 Subject: CURLE_TLSAUTH_FAILED: removed On second thought, I think CURLE_TLSAUTH_FAILED should be eliminated. It was only being raised when an internal error occurred while allocating or setting the GnuTLS SRP client credentials struct. For TLS authentication failures, the general CURLE_SSL_CONNECT_ERROR seems appropriate; its error string already includes "passwords" as a possible cause. Having a separate TLS auth error code might also cause people to think that a TLS auth failure means the wrong username or password was entered, when it could also be a sign of a man-in-the-middle attack. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 89174edf2..71ceb34d9 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -354,7 +354,7 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); - return CURLE_TLSAUTH_FAILED; + return CURLE_OUT_OF_MEMORY; } rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].srp_client_cred, @@ -363,7 +363,7 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); - return CURLE_TLSAUTH_FAILED; + return CURLE_BAD_FUNCTION_ARGUMENT; } } #endif -- cgit v1.2.1 From b903186fa0189ff241d756d25d07fdfe9885ae49 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Apr 2011 15:17:42 +0200 Subject: source cleanup: unify look, style and indent levels By the use of a the new lib/checksrc.pl script that checks that our basic source style rules are followed. --- lib/gtls.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 71ceb34d9..1a2dfd467 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -197,14 +197,14 @@ static gnutls_datum load_file (const char *file) long filelen; void *ptr; - if (!(f = fopen(file, "r"))) + if(!(f = fopen(file, "r"))) return loaded_file; - if (fseek(f, 0, SEEK_END) != 0 - || (filelen = ftell(f)) < 0 - || fseek(f, 0, SEEK_SET) != 0 - || !(ptr = malloc((size_t)filelen))) + if(fseek(f, 0, SEEK_END) != 0 + || (filelen = ftell(f)) < 0 + || fseek(f, 0, SEEK_SET) != 0 + || !(ptr = malloc((size_t)filelen))) goto out; - if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { + if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { free(ptr); goto out; } @@ -282,7 +282,7 @@ static CURLcode handshake(struct connectdata *conn, if(nonblocking) return CURLE_OK; } - else if (rc < 0) { + else if(rc < 0) { failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } @@ -357,7 +357,8 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].srp_client_cred, + rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. + srp_client_cred, data->set.ssl.username, data->set.ssl.password); if(rc != GNUTLS_E_SUCCESS) { @@ -412,13 +413,13 @@ gtls_connect_step1(struct connectdata *conn, /* convenient assign */ session = conn->ssl[sockindex].session; - if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif - sni && - (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, - strlen(conn->host.name)) < 0)) + sni && + (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, + strlen(conn->host.name)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -447,7 +448,8 @@ gtls_connect_step1(struct connectdata *conn, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) { + do_file_type(data->set.str[STRING_CERT_TYPE]) ) != + GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } @@ -458,10 +460,10 @@ gtls_connect_step1(struct connectdata *conn, if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); - if (rc != GNUTLS_E_SUCCESS) { + if(rc != GNUTLS_E_SUCCESS) failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); - } - } else + } + else #endif rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); @@ -586,13 +588,13 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - if (data->set.ssl.issuercert) { + if(data->set.ssl.issuercert) { gnutls_x509_crt_init(&x509_issuer); issuerp = load_file(data->set.ssl.issuercert); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer); unload_file(issuerp); - if (rc <= 0) { + if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); return CURLE_SSL_ISSUER_ERROR; @@ -743,7 +745,7 @@ after_server_cert_verification: gnutls_session_get_data(session, connect_sessionid, &connect_idsize); incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); - if (incache) { + if(incache) { /* there was one before in the cache, so instead of risking that the previous one was rejected, we just kill that and store the new */ Curl_ssl_delsessionid(conn, ssl_sessionid); @@ -869,7 +871,7 @@ static void close_one(struct connectdata *conn, conn->ssl[idx].cred = NULL; } #ifdef USE_TLS_SRP - if (conn->ssl[idx].srp_client_cred) { + if(conn->ssl[idx].srp_client_cred) { gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); conn->ssl[idx].srp_client_cred = NULL; } -- cgit v1.2.1 From 889d1e973fb718a77c5000141d724ce03863af23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 22 Apr 2011 23:01:30 +0200 Subject: whitespace cleanup: no space first in conditionals "if(a)" is our style, not "if( a )" --- lib/gtls.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 1a2dfd467..32d81d46b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -443,13 +443,13 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; if(data->set.str[STRING_CERT]) { - if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ) != - GNUTLS_E_SUCCESS) { + if(gnutls_certificate_set_x509_key_file( + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ) != + GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } -- cgit v1.2.1 From d4e000906ac4ef243258a5c9a819a7cde247d16a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 18 May 2011 20:48:42 +0200 Subject: GnuTLS handshake: fix timeout Commit cbf4961bf3e garbled the timeout handling while doing SSL handshaking (in an attempt at fixing another bug). This puts sanity back. Bug: http://curl.haxx.se/mail/lib-2011-05/0167.html Reported by: Ethan Glasser Camp --- lib/gtls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 32d81d46b..bb2ee1068 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -255,7 +255,8 @@ static CURLcode handshake(struct connectdata *conn, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_ready(readfd, writefd, - nonblocking?0:(int)timeout_ms?1000:timeout_ms); + nonblocking?0: + ((int)timeout_ms?timeout_ms:1000)); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); -- cgit v1.2.1 From 4f170ee8f9c1d067022300df2da331c30dcda9dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 4 Jun 2011 21:19:14 +0200 Subject: Curl_socket_ready: make timeout a 'long' It was mostly typecasted to int all over the code so switching to long instead all over should be a net gain. --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index bb2ee1068..a376fb0b9 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -256,7 +256,7 @@ static CURLcode handshake(struct connectdata *conn, what = Curl_socket_ready(readfd, writefd, nonblocking?0: - ((int)timeout_ms?timeout_ms:1000)); + timeout_ms?timeout_ms:1000); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -907,7 +907,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(conn->ssl[sockindex].session) { while(!done) { int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ -- cgit v1.2.1 From f1586cb4775681810afd8e6626e7842d459f3b85 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 26 Jul 2011 17:23:27 +0200 Subject: stdio.h, stdlib.h, string.h, stdarg.h and ctype.h inclusion done in setup_once.h --- lib/gtls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a376fb0b9..f75a81576 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -29,14 +29,13 @@ */ #include "setup.h" + #ifdef USE_GNUTLS + #include #include #include -#include -#include -#include #ifdef HAVE_SYS_SOCKET_H #include #endif -- cgit v1.2.1 From 8036da870c5b413a83097b3486c58d13910a471a Mon Sep 17 00:00:00 2001 From: Tim Harder Date: Wed, 19 Oct 2011 10:08:56 +0200 Subject: gtls: only call gnutls_transport_set_lowat with =gnutls-3 which causes build failures. Therefore, the function shouldn't be used except for versions that require it, Date: Sat, 29 Oct 2011 14:58:50 +0200 Subject: gtls.c: gnutls_transport_set_global_errno() deprecated in version 2.12.3 --- lib/gtls.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 7ca46c812..c1e9cae51 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -78,6 +78,17 @@ static void tls_log_func(int level, const char *str) #endif static bool gtls_inited = FALSE; +#if defined(GNUTLS_VERSION_NUMBER) +# if (GNUTLS_VERSION_NUMBER >= 0x020c00) +# undef gnutls_transport_set_lowat +# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt +# endif +# if (GNUTLS_VERSION_NUMBER >= 0x020c03) +# undef gnutls_transport_set_global_errno +# define gnutls_transport_set_global_errno(A) SET_ERRNO((A)) +# endif +#endif + /* * Custom push and pull callback functions used by GNU TLS to read and write * to the socket. These functions are simple wrappers to send() and recv() @@ -476,10 +487,8 @@ gtls_connect_step1(struct connectdata *conn, gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_pull_function(session, Curl_gtls_pull); -#if GNUTLS_VERSION_NUMBER < 0x020c00 /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); -#endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ -- cgit v1.2.1 From a873b95c21700e8e75db7e62b5ac5ef8fc8c9b03 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 2 Nov 2011 22:44:22 +0100 Subject: gtls_connect_step1: remove use of deprecated functions Use gnutls_priority_set_direct() instead of gnutls_protocol_set_priority(). Remove the gnutls_certificate_type_set_priority() use since x509 is the default certificate type anyway. Reported by: Vincent Torri --- lib/gtls.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index c1e9cae51..ed79313f8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -82,6 +82,7 @@ static bool gtls_inited = FALSE; # if (GNUTLS_VERSION_NUMBER >= 0x020c00) # undef gnutls_transport_set_lowat # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt +# define USE_GNUTLS_PRIORITY_SET_DIRECT 1 # endif # if (GNUTLS_VERSION_NUMBER >= 0x020c03) # undef gnutls_transport_set_global_errno @@ -320,7 +321,9 @@ static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; +#endif struct SessionHandle *data = conn->data; gnutls_session session; int rc; @@ -440,18 +443,26 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static const int protocol_priority[] = { GNUTLS_SSL3, 0 }; - gnutls_protocol_set_priority(session, protocol_priority); + rc = gnutls_protocol_set_priority(session, protocol_priority); +#else + const char *err; + rc = gnutls_priority_set_direct(session, "-VERS-TLS-ALL:+VERS-SSL3.0", + &err); +#endif if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; } +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; +#endif if(data->set.str[STRING_CERT]) { if(gnutls_certificate_set_x509_key_file( -- cgit v1.2.1 From 64f328c787ab763cc994eadd6b82f32490d37ebb Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Tue, 15 Nov 2011 11:52:32 +0200 Subject: Add support for using nettle instead of gcrypt as gnutls backend --- lib/gtls.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index ed79313f8..a98a7e87c 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -34,7 +34,9 @@ #include #include +#ifndef USE_GNUTLS_NETTLE #include +#endif #ifdef HAVE_SYS_SOCKET_H #include @@ -1032,7 +1034,9 @@ int Curl_gtls_seed(struct SessionHandle *data) static bool ssl_seeded = FALSE; /* Quickly add a bit of entropy */ +#ifndef USE_GNUTLS_NETTLE gcry_fast_random_poll(); +#endif if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || data->set.str[STRING_SSL_EGDSOCKET]) { -- cgit v1.2.1 From 28bac99674f199898f3e803fcfc4167a56a4c058 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 22 Nov 2011 22:48:15 +0100 Subject: gnutls: only translate winsock errors for old versions Bugfix: https handshake fails using gnutls 3 on windows http://sourceforge.net/tracker/index.php?func=detail&aid=3441084&group_id=976&atid=100976 New gnutls versions have an error handler that knows about Winsock errors, which is why gnutls_transport_set_global_errno() was deprecated and then removed. This is a correction of commit f5bb370 (blame me) which meant to reimplement gnutls_transport_set_global_errno(), which is not necessary. --- lib/gtls.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a98a7e87c..c64c8c4b4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -80,15 +80,17 @@ static void tls_log_func(int level, const char *str) #endif static bool gtls_inited = FALSE; +#undef MAP_WINSOCK_ERRORS #if defined(GNUTLS_VERSION_NUMBER) # if (GNUTLS_VERSION_NUMBER >= 0x020c00) # undef gnutls_transport_set_lowat # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt # define USE_GNUTLS_PRIORITY_SET_DIRECT 1 # endif -# if (GNUTLS_VERSION_NUMBER >= 0x020c03) -# undef gnutls_transport_set_global_errno -# define gnutls_transport_set_global_errno(A) SET_ERRNO((A)) +# if (GNUTLS_VERSION_NUMBER < 0x020c03) +# ifdef USE_WINSOCK +# define MAP_WINSOCK_ERRORS +# endif # endif #endif @@ -100,6 +102,7 @@ static bool gtls_inited = FALSE; * us to get specific about the fourth "flags" argument, and to use arbitrary * private data with gnutls_transport_set_ptr if we wish. * + * For old gnutls versions, curl must translate Winsock errors: * When these custom push and pull callbacks fail, GNU TLS checks its own * session-specific error variable, and when not set also its own global * errno variable, in order to take appropriate action. GNU TLS does not @@ -111,7 +114,7 @@ static bool gtls_inited = FALSE; * error translation must take place in these callbacks. */ -#ifdef USE_WINSOCK +#ifdef MAP_WINSOCK_ERRORS # define gtls_EINTR 4 # define gtls_EIO 5 # define gtls_EAGAIN 11 @@ -132,7 +135,7 @@ static int gtls_mapped_sockerrno(void) static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef USE_WINSOCK +#ifdef MAP_WINSOCK_ERRORS if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif @@ -142,7 +145,7 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef USE_WINSOCK +#ifdef MAP_WINSOCK_ERRORS if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif -- cgit v1.2.1 From 78feaff9d800efb5d1f97f8653721718a6cf00c8 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Thu, 24 Nov 2011 12:11:52 +0100 Subject: Fix unreleased regression when using windows gnutls versions older than 2.8 --- lib/gtls.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index c64c8c4b4..a2e8d9931 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -80,17 +80,14 @@ static void tls_log_func(int level, const char *str) #endif static bool gtls_inited = FALSE; -#undef MAP_WINSOCK_ERRORS #if defined(GNUTLS_VERSION_NUMBER) # if (GNUTLS_VERSION_NUMBER >= 0x020c00) # undef gnutls_transport_set_lowat # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt # define USE_GNUTLS_PRIORITY_SET_DIRECT 1 # endif -# if (GNUTLS_VERSION_NUMBER < 0x020c03) -# ifdef USE_WINSOCK -# define MAP_WINSOCK_ERRORS -# endif +# if (GNUTLS_VERSION_NUMBER >= 0x020c03) +# define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif #endif @@ -102,7 +99,6 @@ static bool gtls_inited = FALSE; * us to get specific about the fourth "flags" argument, and to use arbitrary * private data with gnutls_transport_set_ptr if we wish. * - * For old gnutls versions, curl must translate Winsock errors: * When these custom push and pull callbacks fail, GNU TLS checks its own * session-specific error variable, and when not set also its own global * errno variable, in order to take appropriate action. GNU TLS does not @@ -112,9 +108,13 @@ static bool gtls_inited = FALSE; * resort global errno variable using gnutls_transport_set_global_errno, * with a transport agnostic error value. This implies that some winsock * error translation must take place in these callbacks. + * + * Paragraph above applies to GNU TLS versions older than 2.12.3, since + * this version GNU TLS does its own internal winsock error translation + * using system_errno() function. */ -#ifdef MAP_WINSOCK_ERRORS +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) # define gtls_EINTR 4 # define gtls_EIO 5 # define gtls_EAGAIN 11 @@ -135,7 +135,7 @@ static int gtls_mapped_sockerrno(void) static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef MAP_WINSOCK_ERRORS +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif @@ -145,7 +145,7 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef MAP_WINSOCK_ERRORS +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif -- cgit v1.2.1 From 0ce2bca741ae596a346b2ab767dfbf5be9bc7dae Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 16 Jan 2012 21:14:05 +0100 Subject: add LF termination to infof() trace string --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a2e8d9931..f44fd7748 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -203,7 +203,7 @@ static void showtime(struct SessionHandle *data, tm->tm_hour, tm->tm_min, tm->tm_sec); - infof(data, "%s", data->state.buffer); + infof(data, "%s\n", data->state.buffer); } static gnutls_datum load_file (const char *file) -- cgit v1.2.1 From 70f71bb99f7ed9f4164430507c0b03b84c7e0258 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 23 Jan 2012 23:53:06 +0100 Subject: gnutls: enforced use of SSLv3 With advice from Nikos Mavrogiannopoulos, changed the priority string to add "actual priorities" and favour ARCFOUR. This makes libcurl work better when enforcing SSLv3 with GnuTLS. Both in the sense that the libmicrohttpd test is now working again but also that it mitigates a weakness in the older SSL/TLS protocols. Bug: http://curl.haxx.se/mail/lib-2012-01/0225.html Reported by: Christian Grothoff --- lib/gtls.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f44fd7748..e24e7a81e 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -453,7 +453,13 @@ gtls_connect_step1(struct connectdata *conn, rc = gnutls_protocol_set_priority(session, protocol_priority); #else const char *err; - rc = gnutls_priority_set_direct(session, "-VERS-TLS-ALL:+VERS-SSL3.0", + /* the combination of the cipher ARCFOUR with SSL 3.0 and TLS 1.0 is not + vulnerable to attacks such as the BEAST, why this code now explicitly + asks for that + */ + rc = gnutls_priority_set_direct(session, + "NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0:" + "-CIPHER-ALL:+ARCFOUR-128", &err); #endif if(rc != GNUTLS_E_SUCCESS) -- cgit v1.2.1 From 6085ca2aeddb38e4d5f24c47bd98111b236cf384 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Thu, 14 Jun 2012 13:32:05 +0200 Subject: Fix bad failf() and info() usage Calls to failf() are not supposed to provide trailing newline. Calls to infof() must provide trailing newline. Fixed 30 or so strings. --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index e24e7a81e..f77bbc5fd 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -413,7 +413,7 @@ gtls_connect_step1(struct connectdata *conn, data->set.ssl.CRLfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { - failf(data, "error reading crl file %s (%s)\n", + failf(data, "error reading crl file %s (%s)", data->set.ssl.CRLfile, gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } -- cgit v1.2.1 From 849179ba2739ab9a0ad079384b125d9c1745db5f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 26 Jun 2012 14:52:46 +0200 Subject: SSL cleanup: use crypto functions through the sslgen layer curl_ntlm_msgs.c would previously use an #ifdef maze and direct SSL-library calls instead of using the SSL layer we have for this purpose. --- lib/gtls.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f77bbc5fd..d981ef1eb 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -1060,4 +1060,36 @@ int Curl_gtls_seed(struct SessionHandle *data) return 0; } +void Curl_gtls_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ +#if defined(USE_GNUTLS_NETTLE) + (void)data; + gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); +#elif defined(USE_GNUTLS) + Curl_gtls_seed(data); /* Initiate the seed if not already done */ + gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); +#endif +} + +void Curl_gtls_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ +#if defined(USE_GNUTLS_NETTLE) + struct md5_ctx MD5pw; + md5_init(&MD5pw); + md5_update(&MD5pw, tmplen, tmp); + md5_digest(&MD5pw, md5len, md5sum); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD5pw; + gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); + gcry_md_write(MD5pw, tmp, tmplen); + memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len); + gcry_md_close(MD5pw); +#endif +} + #endif /* USE_GNUTLS */ -- cgit v1.2.1 From 986c7949c0638bebb99bd08d63216433254c2185 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Aug 2012 15:04:25 +0200 Subject: gtls: fix build failure by including nettle-specific headers Bug: http://curl.haxx.se/bug/view.cgi?id=3554668 Reported by: Anthony G. Basile --- lib/gtls.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index d981ef1eb..c750a6f90 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -34,7 +34,10 @@ #include #include -#ifndef USE_GNUTLS_NETTLE +#ifdef USE_GNUTLS_NETTLE +#include +#include +#else #include #endif -- cgit v1.2.1 From ee3551e45e60856eb0b779aa6cd34d77f16208a5 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Mon, 20 Aug 2012 16:47:48 +0200 Subject: gnutls: do not fail on non-fatal handshake errors Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=685402 --- lib/gtls.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index c750a6f90..3b4dc40a3 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -302,15 +302,17 @@ static CURLcode handshake(struct connectdata *conn, if(nonblocking) return CURLE_OK; } + else if((rc < 0) && gnutls_error_is_fatal(rc)) { + failf(data, "gnutls_handshake() warning: %s", gnutls_strerror(rc)); + } else if(rc < 0) { failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } - else { - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; - } + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; } } -- cgit v1.2.1 From 1a02e84589efb3f8717d50bdc78d3f369b799198 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Mon, 15 Oct 2012 16:06:54 +0200 Subject: gnutls: put reset code into else block Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=690551 --- lib/gtls.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index 3b4dc40a3..f5f95aef8 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -309,10 +309,11 @@ static CURLcode handshake(struct connectdata *conn, failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; + else { + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; + } } } -- cgit v1.2.1 From 2045d83dd3f478f7bb8ef86959a82c96235b2bca Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 24 Oct 2012 11:47:32 +0200 Subject: gnutls: fix the error_is_fatal logic --- lib/gtls.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index f5f95aef8..dbf568c44 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -299,21 +299,21 @@ static CURLcode handshake(struct connectdata *conn, connssl->connecting_state = gnutls_record_get_direction(session)? ssl_connect_2_writing:ssl_connect_2_reading; + continue; if(nonblocking) return CURLE_OK; } - else if((rc < 0) && gnutls_error_is_fatal(rc)) { + else if((rc < 0) && !gnutls_error_is_fatal(rc)) { failf(data, "gnutls_handshake() warning: %s", gnutls_strerror(rc)); } else if(rc < 0) { failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } - else { - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; - } + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; } } -- cgit v1.2.1 From 41eec4efa2a8c653973b25240c5cda81bb12e26f Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 24 Oct 2012 14:34:00 +0200 Subject: gnutls: print alerts during handshake --- lib/gtls.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index dbf568c44..d8e88e2c4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -304,10 +304,30 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OK; } else if((rc < 0) && !gnutls_error_is_fatal(rc)) { - failf(data, "gnutls_handshake() warning: %s", gnutls_strerror(rc)); + char *strerr = NULL; + + if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(strerr == NULL) + strerr = gnutls_strerror(rc); + + failf(data, "gnutls_handshake() warning: %s", strerr); } else if(rc < 0) { - failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); + char *strerr = NULL; + + if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(strerr == NULL) + strerr = gnutls_strerror(rc); + + failf(data, "gnutls_handshake() failed: %s", strerr); return CURLE_SSL_CONNECT_ERROR; } -- cgit v1.2.1 From ab1f80200a6d1bcbac167ede429be52f3ef838bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 6 Nov 2012 19:45:51 +0100 Subject: gnutls: fix compiler warnings --- lib/gtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index d8e88e2c4..a17d9eeda 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -304,7 +304,7 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OK; } else if((rc < 0) && !gnutls_error_is_fatal(rc)) { - char *strerr = NULL; + const char *strerr = NULL; if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { int alert = gnutls_alert_get(session); @@ -317,7 +317,7 @@ static CURLcode handshake(struct connectdata *conn, failf(data, "gnutls_handshake() warning: %s", strerr); } else if(rc < 0) { - char *strerr = NULL; + const char *strerr = NULL; if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { int alert = gnutls_alert_get(session); -- cgit v1.2.1 From da82f59b697310229ccdf66104d5d65a44dfab98 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 27 Oct 2012 12:31:39 +0200 Subject: CURLOPT_SSL_VERIFYHOST: stop supporting the 1 value After a research team wrote a document[1] that found several live source codes out there in the wild that misused the CURLOPT_SSL_VERIFYHOST option thinking it was a boolean, this change now bans 1 as a value and will make libcurl return error for it. 1 was never a sensible value to use in production but was introduced back in the days to help debugging. It was always documented clearly this way. 1 was never supported by all SSL backends in libcurl, so this cleanup makes the treatment of it unified. The report's list of mistakes for this option were all PHP code and while there's a binding layer between libcurl and PHP, the PHP team has decided that they have an as thin layer as possible on top of libcurl so they will not alter or specifically filter a 'TRUE' value for this particular option. I sympathize with that position. [1] = http://daniel.haxx.se/blog/2012/10/25/libcurl-claimed-to-be-dangerous/ --- lib/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/gtls.c') diff --git a/lib/gtls.c b/lib/gtls.c index a17d9eeda..2920ee2f9 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -681,7 +681,7 @@ gtls_connect_step3(struct connectdata *conn, rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); if(!rc) { - if(data->set.ssl.verifyhost > 1) { + if(data->set.ssl.verifyhost) { failf(data, "SSL: certificate subject name (%s) does not match " "target host name '%s'", certbuf, conn->host.dispname); gnutls_x509_crt_deinit(x509_cert); -- cgit v1.2.1