diff --git a/configure.ac b/configure.ac index 92adc5032..e3b69d0fa 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,7 @@ dnl initialize all the info variables curl_krb4_msg="no (--with-krb4*)" curl_gss_msg="no (--with-gssapi)" curl_spnego_msg="no (--with-spnego)" +curl_tls_srp_msg="no (--enable-tls-srp)" curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" curl_ipv6_msg="no (--enable-ipv6)" curl_idn_msg="no (--with-libidn)" @@ -1754,6 +1755,17 @@ if test "$GNUTLS_ENABLED" = "1"; then ]) fi +dnl --- +dnl We require GnuTLS with SRP support. +dnl --- +if test "$GNUTLS_ENABLED" = "1"; then + AC_CHECK_LIB(gnutls, gnutls_srp_verifier, + [ + AC_DEFINE(HAVE_GNUTLS_SRP, 1, [if you have the function gnutls_srp_verifier]) + AC_SUBST(HAVE_GNUTLS_SRP, [1]) + ]) +fi + dnl ---------------------------------------------------- dnl check for PolarSSL dnl ---------------------------------------------------- @@ -2654,6 +2666,32 @@ AC_HELP_STRING([--disable-crypto-auth],[Disable cryptographic authentication]), AC_MSG_RESULT(yes) ) +dnl ************************************************************ +dnl disable TLS-SRP authentication +dnl +AC_MSG_CHECKING([whether to enable TLS-SRP authentication]) +AC_ARG_ENABLE(tls-srp, +AC_HELP_STRING([--enable-tls-srp],[Enable TLS-SRP authentication]) +AC_HELP_STRING([--disable-tls-srp],[Disable TLS-SRP authentication]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_TLS_SRP, 1, [to disable TLS-SRP authentication]) + want_tls_srp=no + ;; + *) AC_MSG_RESULT(yes) + want_tls_srp=yes + ;; + esac ], + AC_MSG_RESULT(yes) + want_tls_srp=yes +) + +if test "$want_tls_srp" = "yes" && test "x$HAVE_GNUTLS_SRP" = "x1"; then + AC_DEFINE(USE_TLS_SRP, 1, [Use TLS-SRP authentication]) + curl_tls_srp_msg="enabled" +fi + dnl ************************************************************ dnl disable cookies support dnl @@ -2802,6 +2840,9 @@ if test "x$USE_SSLEAY" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \ -o "x$GNUTLS_ENABLED" = "x1" -o "x$NSS_ENABLED" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM" fi +if test "x$USE_TLS_SRP" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES TLS-SRP" +fi AC_SUBST(SUPPORT_FEATURES) @@ -2945,6 +2986,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: krb4 support: ${curl_krb4_msg} GSSAPI support: ${curl_gss_msg} SPNEGO support: ${curl_spnego_msg} + TLS-SRP support: ${curl_tls_srp_msg} resolver: ${curl_res_msg} ipv6 support: ${curl_ipv6_msg} IDN support: ${curl_idn_msg} diff --git a/include/curl/curl.h b/include/curl/curl.h index fbd0d9b01..bf6542076 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -502,6 +502,7 @@ typedef enum { CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Identifiers */ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_TLSAUTH_FAILED, /* 89 - Failed TLS authentication */ CURL_LAST /* never use! */ } CURLcode; @@ -1442,6 +1443,15 @@ typedef enum { /* send linked-list of name:port:address sets */ CINIT(RESOLVE, OBJECTPOINT, 203), + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1538,6 +1548,12 @@ enum { CURL_SSLVERSION_LAST /* never use, keep last */ }; +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + /* symbols to use with CURLOPT_POSTREDIR. CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */ @@ -2043,6 +2059,7 @@ typedef struct { #define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ #define CURL_VERSION_CONV (1<<12) /* character conversions supported */ #define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ /* * NAME curl_version_info() 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; diff --git a/lib/strerror.c b/lib/strerror.c index e8ecea59f..6b67a8777 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 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 @@ -281,6 +281,9 @@ curl_easy_strerror(CURLcode error) case CURLE_CHUNK_FAILED: return "Chunk callback failed"; + case CURLE_TLSAUTH_FAILED: + return "TLS Authentication failed"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE4: case CURLE_OBSOLETE10: diff --git a/lib/url.c b/lib/url.c index f8bd07aad..cd89e1f89 100644 --- a/lib/url.c +++ b/lib/url.c @@ -751,6 +751,9 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) */ set->ssl.verifypeer = TRUE; set->ssl.verifyhost = 2; +#ifdef USE_TLS_SRP + set->ssl.authtype = CURL_TLSAUTH_NONE; +#endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ set->ssl.sessionid = TRUE; /* session ID caching enabled by default */ @@ -2526,6 +2529,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_FNMATCH_DATA: data->set.fnmatch_data = va_arg(param, void *); break; +#ifdef USE_TLS_SRP + case CURLOPT_TLSAUTH_USERNAME: + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + va_arg(param, char *)); + if (data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + va_arg(param, char *)); + if (data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_TLSAUTH_TYPE: + if (strncmp((char *)va_arg(param, char *), "SRP", strlen("SRP")) == 0) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; + else + data->set.ssl.authtype = CURL_TLSAUTH_NONE; + break; +#endif default: /* unknown tag and its companion, just ignore: */ result = CURLE_FAILED_INIT; /* correct this */ @@ -4929,6 +4952,10 @@ static CURLcode create_conn(struct SessionHandle *data, data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; +#ifdef USE_TLS_SRP + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#endif if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) return CURLE_OUT_OF_MEMORY; diff --git a/lib/urldata.h b/lib/urldata.h index 55167fbc3..a86f7f156 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -251,6 +251,9 @@ struct ssl_connect_data { #ifdef USE_GNUTLS gnutls_session session; gnutls_certificate_credentials cred; +#ifdef USE_TLS_SRP + gnutls_srp_client_credentials srp_client_cred; +#endif ssl_connect_state connecting_state; #endif /* USE_GNUTLS */ #ifdef USE_POLARSSL @@ -300,6 +303,12 @@ struct ssl_config_data { void *fsslctxp; /* parameter for call back */ bool sessionid; /* cache session IDs or not */ bool certinfo; /* gather lots of certificate info */ + +#ifdef USE_TLS_SRP + char *username; /* TLS username (for, e.g., SRP) */ + char *password; /* TLS password (for, e.g., SRP) */ + enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +#endif }; /* information stored about one single SSL session */ @@ -1315,6 +1324,11 @@ enum dupstring { #endif STRING_MAIL_FROM, +#ifdef USE_TLS_SRP + STRING_TLSAUTH_USERNAME, /* TLS auth */ + STRING_TLSAUTH_PASSWORD, /* TLS auth */ +#endif + /* -- end of strings -- */ STRING_LAST /* not used, just an end-of-list marker */ }; diff --git a/lib/version.c b/lib/version.c index 5931e7180..52989cdc6 100644 --- a/lib/version.c +++ b/lib/version.c @@ -264,6 +264,9 @@ static curl_version_info_data version_info = { #endif #if defined(CURL_DOES_CONVERSIONS) | CURL_VERSION_CONV +#endif +#if defined(USE_TLS_SRP) + | CURL_VERSION_TLSAUTH_SRP #endif , NULL, /* ssl_version */ diff --git a/src/main.c b/src/main.c index 7e2e34ece..d8a105ea7 100644 --- a/src/main.c +++ b/src/main.c @@ -503,6 +503,9 @@ struct Configurable { long low_speed_time; bool showerror; char *userpwd; + char *tls_username; + char *tls_password; + char *tls_authtype; char *proxyuserpwd; char *proxy; int proxyver; /* set to CURLPROXY_HTTP* define */ @@ -903,6 +906,11 @@ static void help(void) " --url Set URL to work with", " -B/--use-ascii Use ASCII/text transfer", " -u/--user Set server user and password", +#ifdef USE_TLS_SRP + " --tlsuser Set TLS username", + " --tlspassword Set TLS password", + " --tlsauthtype Set TLS authentication type (default SRP)", +#endif " -A/--user-agent User-Agent to send to server (H)", " -v/--verbose Make the operation more talkative", " -V/--version Show version number and quit", @@ -1916,6 +1924,11 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ {"Eh","pubkey", TRUE}, {"Ei", "hostpubmd5", TRUE}, {"Ej","crlfile", TRUE}, +#ifdef USE_TLS_SRP + {"Ek","tlsuser", TRUE}, + {"El","tlspassword", TRUE}, + {"Em","tlsauthtype", TRUE}, +#endif {"f", "fail", FALSE}, {"F", "form", TRUE}, {"Fs","form-string", TRUE}, @@ -2744,6 +2757,28 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ /* CRL file */ GetStr(&config->crlfile, nextarg); break; +#ifdef USE_TLS_SRP + case 'k': /* TLS username */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->tls_username, nextarg); + } else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'l': /* TLS password */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->tls_password, nextarg); + } else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'm': /* TLS authentication type */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->tls_authtype, nextarg); + if (strncmp(config->tls_authtype, "SRP", strlen("SRP")) != 0) + return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; +#endif default: /* certificate file */ { char *ptr = strchr(nextarg, ':'); @@ -3122,7 +3157,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ {"SSPI", CURL_VERSION_SSPI}, {"krb4", CURL_VERSION_KERBEROS4}, {"libz", CURL_VERSION_LIBZ}, - {"CharConv", CURL_VERSION_CONV} + {"CharConv", CURL_VERSION_CONV}, + {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP} }; printf("Features: "); for(i=0; ihostpubmd5); if(config->mail_from) free(config->mail_from); +#ifdef USE_TLS_SRP + if(config->tls_authtype) + free(config->tls_authtype); + if(config->tls_username) + free(config->tls_username); + if(config->tls_password) + free(config->tls_password); +#endif #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(config->socks5_gssapi_service) free(config->socks5_gssapi_service); @@ -5462,6 +5506,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) /* new in 7.21.3 */ my_setopt(curl, CURLOPT_RESOLVE, config->resolve); + /* TODO: new in ### */ + curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username); + curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password); + retry_numretries = config->req_retry; retrystart = cutil_tvnow(); diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT index f4565d32e..05d622f33 100644 --- a/tests/FILEFORMAT +++ b/tests/FILEFORMAT @@ -158,6 +158,7 @@ rtsp-ipv6 imap pop3 smtp +http+tls-srp Give only one per line. This subsection is mandatory. diff --git a/tests/certs/srp-verifier-conf b/tests/certs/srp-verifier-conf new file mode 100644 index 000000000..67825ceab --- /dev/null +++ b/tests/certs/srp-verifier-conf @@ -0,0 +1,3 @@ +1:Ewl2hcjiutMd3Fu2lgFnUXWSc67TVyy2vwYCKoS9MLsrdJVT9RgWTCuEqWJrfB6uE3LsE9GkOlaZabS7M29sj5TnzUqOLJMjiwEzArfiLr9WbMRANlF68N5AVLcPWvNx6Zjl3m5Scp0BzJBz9TkgfhzKJZ.WtP3Mv/67I/0wmRZ:2 +2:dUyyhxav9tgnyIg65wHxkzkb7VIPh4o0lkwfOKiPp4rVJrzLRYVBtb76gKlaO7ef5LYGEw3G.4E0jbMxcYBetDy2YdpiP/3GWJInoBbvYHIRO9uBuxgsFKTKWu7RnR7yTau/IrFTdQ4LY/q.AvoCzMxV0PKvD9Odso/LFIItn8PbTov3VMn/ZEH2SqhtpBUkWtmcIkEflhX/YY/fkBKfBbe27/zUaKUUZEUYZ2H2nlCL60.JIPeZJSzsu/xHDVcx:2 +3:2iQzj1CagQc/5ctbuJYLWlhtAsPHc7xWVyCPAKFRLWKADpASkqe9djWPFWTNTdeJtL8nAhImCn3Sr/IAdQ1FrGw0WvQUstPx3FO9KNcXOwisOQ1VlL.gheAHYfbYyBaxXL.NcJx9TUwgWDT0hRzFzqSrdGGTN3FgSTA1v4QnHtEygNj3eZ.u0MThqWUaDiP87nqha7XnT66bkTCkQ8.7T8L4KZjIImrNrUftedTTBi.WCi.zlrBxDuOM0da0JbUkQlXqvp0yvJAPpC11nxmmZOAbQOywZGmu9nhZNuwTlxjfIro0FOdthaDTuZRL9VL7MRPUDo/DQEyW.d4H.UIlzp:2 diff --git a/tests/certs/srp-verifier-db b/tests/certs/srp-verifier-db new file mode 100644 index 000000000..2f851a342 --- /dev/null +++ b/tests/certs/srp-verifier-db @@ -0,0 +1,2 @@ +jsmith:34fPk7u.w3R/M1k2sQ9F.04GZqLKAsqDn44CHGu7ML0M8VWwu1p79OLxi6jRhSNdSM46Kx9GRVyJLXz7eok53..A6X5p3NdnMSYX8WwYrDmuseHDr.eua7gjd04S4EoY4ZuKix2.WGAsMTwk86AmTvcqyzqsH7GDhGOHEhjP5zs:lTjBBoK04K9vTKiL10rI/:1 +alice:3IIP1g1HDTN6VEUr8DUkMleocoC1cpuFZnmunDaGhMyIsw8LAwCc7ZapWaC66gZSyis4ezSuCqvhsJdwdc.0es2UrH6PBkBQflcQDuC.dEpjhWgAcH2Dw.2qU.E0ApQzLkcKOjXMQ2R6jMBL14kEUPjjHS3aa16yB.Afj3bNPdf:1JxU4GkweUEii6.b0grkzU:1 diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 701b32415..6f4e77a6b 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -69,7 +69,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \ test569 test570 test571 test572 test804 test805 test806 test807 test573 \ test313 test1115 test578 test579 test1116 test1200 test1201 test1202 \ test1203 test1117 test1118 test1119 test1120 test1300 test1301 test1302 \ - test1303 + test1303 test320 test321 test322 test323 test324 filecheck: @mkdir test-place; \ diff --git a/tests/data/test320 b/tests/data/test320 new file mode 100644 index 000000000..bfef00cb2 --- /dev/null +++ b/tests/data/test320 @@ -0,0 +1,95 @@ + + + +HTTPS +HTTP GET +TLS-SRP + + + +# Server-side + + +HTTP/1.0 200 OK +Content-type: text/html + + + +

This is GNUTLS

+ + +

Session ID: 003030000100000001000000000000000030330001000000B062410001000000

+
If your browser supports session resuming, then you should see the same session ID, when you press the reload button.
+

Connected as user 'jsmith'.

+

+ + + + + +

Protocol version:TLS1.2
Key Exchange:SRP
CompressionNULL
CipherAES-128-CBC
MACSHA1
CiphersuiteSRP_SHA_AES_128_CBC_SHA1
+


Your HTTP header was:

User-Agent: curl/7.21.4-DEV (x86_64-apple-darwin10.5.0) libcurl/7.21.4-DEV GnuTLS/2.10.4 zlib/1.2.5 libidn/1.19
+Host: localhost:9011
+Accept: */*
+
+

+ + +
+
+ +# Client-side + + +http+tls-srp + + +TLS-SRP + + +simple TLS-SRP HTTPS GET, check user in response + + +--insecure --tlsauthtype SRP --tlsuser jsmith --tlspassword abc https://%HOSTIP:%HTTPTLSSRPPORT + + + +# Verify data after the test has been "shot" + + + + +HTTP/1.0 200 OK +Content-type: text/html + + + +

This is GNUTLS

+ + + +
If your browser supports session resuming, then you should see the same session ID, when you press the reload button.
+

Connected as user 'jsmith'.

+

+ + + + +

+
Key Exchange:SRP
CompressionNULL
CipherAES-128-CBC
MACSHA1
CiphersuiteSRP_SHA_AES_128_CBC_SHA1
+ +Host: %HOSTIP:%HTTPTLSSRPPORT +Accept: */* + +

+ + +
+ +s/^

Session ID:.*// +s/^


Your HTTP header was:.*// +s/Protocol version:.*// + + + + diff --git a/tests/data/test321 b/tests/data/test321 new file mode 100644 index 000000000..84c19bc85 --- /dev/null +++ b/tests/data/test321 @@ -0,0 +1,33 @@ + + + +HTTPS +TLS-SRP +FAILURE + + + +# Client-side + + +http+tls-srp + + +TLS-SRP + + +TLS-SRP with bad username and password + + +--insecure --tlsauthtype SRP --tlsuser baduser --tlspassword badpass https://%HOSTIP:%HTTPTLSSRPPORT + + + +# Verify data after the test has been "shot" + + +35 + + + + diff --git a/tests/data/test322 b/tests/data/test322 new file mode 100644 index 000000000..f44deb54b --- /dev/null +++ b/tests/data/test322 @@ -0,0 +1,33 @@ + + + +HTTPS +TLS-SRP +FAILURE + + + +# Client-side + + +http+tls-srp + + +TLS-SRP + + +TLS-SRP with bad password + + +--insecure --tlsauthtype SRP --tlsuser jsmith --tlspassword badpass https://%HOSTIP:%HTTPTLSSRPPORT + + + +# Verify data after the test has been "shot" + + +35 + + + + diff --git a/tests/data/test323 b/tests/data/test323 new file mode 100644 index 000000000..6439b4d43 --- /dev/null +++ b/tests/data/test323 @@ -0,0 +1,33 @@ + + + +HTTPS +TLS-SRP +FAILURE + + + +# Client-side + + +https + + +TLS-SRP + + +TLS-SRP to non-TLS-SRP server + + +--insecure --tlsauthtype SRP --tlsuser jsmith --tlspassword badpass https://%HOSTIP:%HTTPSPORT/want/323 + + + +# Verify data after the test has been "shot" + + +35 + + + + diff --git a/tests/data/test324 b/tests/data/test324 new file mode 100644 index 000000000..df150ab3c --- /dev/null +++ b/tests/data/test324 @@ -0,0 +1,33 @@ + + + +HTTPS +TLS-SRP +FAILURE + + + +# Client-side + + +http+tls-srp + + +TLS-SRP + + +TLS-SRP with server cert checking + + # no --insecure +--tlsauthtype SRP --tlsuser jsmith --tlspassword abc https://%HOSTIP:%HTTPTLSSRPPORT/want/323 + + + +# Verify data after the test has been "shot" + + +51 + + + + diff --git a/tests/runtests.pl b/tests/runtests.pl index 9f4430694..15461d63d 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -100,6 +100,7 @@ use sshhelp qw( find_sshd find_ssh find_sftp + find_gnutls_serv sshversioninfo ); @@ -135,6 +136,7 @@ my $RTSPPORT; # RTSP my $RTSP6PORT; # RTSP IPv6 server port my $GOPHERPORT; # Gopher my $GOPHER6PORT; # Gopher IPv6 server port +my $HTTPTLSSRPPORT; # TLS-SRP HTTP port my $srcdir = $ENV{'srcdir'} || '.'; my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests @@ -202,6 +204,7 @@ my $has_libz; # set if libcurl is built with libz support my $has_getrlimit; # set if system has getrlimit() my $has_ntlm; # set if libcurl is built with NTLM support my $has_charconv;# set if libcurl is built with CharConv support +my $has_tls_srp; # set if libcurl is built with TLS-SRP support my $has_openssl; # built with a lib using an OpenSSL-like API my $has_gnutls; # built with GnuTLS @@ -334,7 +337,7 @@ sub init_serverpidfile_hash { } } } - for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher')) { + for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher', 'http+tls-srp')) { for my $ipvnum ((4, 6)) { for my $idnum ((1, 2)) { my $serv = servername_id($proto, $ipvnum, $idnum); @@ -957,6 +960,81 @@ sub verifysftp { return $verified; } +####################################################################### +# Verify that the TLS-SRP HTTP server that runs on $ip, $port is our server. +# This also implies that we can speak with it, as there might be occasions when +# the server runs fine but we cannot talk to it ("Failed to connect to ::1: +# Can't assign requested address" # + +sub verifyhttptlssrp { + my ($proto, $ipvnum, $idnum, $ip, $port) = @_; + my $server = servername_id($proto, $ipvnum, $idnum); + my $pidfile = server_pidfilename($proto, $ipvnum, $idnum); + my $pid = 0; + my $bonus=""; + + my $verifyout = "$LOGDIR/". + servername_canon($proto, $ipvnum, $idnum) .'_verify.out'; + unlink($verifyout) if(-f $verifyout); + + my $verifylog = "$LOGDIR/". + servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; + unlink($verifylog) if(-f $verifylog); + + my $flags = "--max-time $server_response_maxtime "; + $flags .= "--output $verifyout "; + $flags .= "--verbose "; + $flags .= "--globoff "; + $flags .= "--insecure "; + $flags .= "--tlsauthtype SRP --tlsuser jsmith --tlspassword abc "; + $flags .= "\"https://$ip:$port/verifiedserver\""; + + my $cmd = "$VCURL $flags 2>$verifylog"; + + # verify if our/any server is running on this port + logmsg "RUN: $cmd\n" if($verbose); + my $res = runclient($cmd); + + $res >>= 8; # rotate the result + if($res & 128) { + logmsg "RUN: curl command died with a coredump\n"; + return -1; + } + + if($res && $verbose) { + logmsg "RUN: curl command returned $res\n"; + if(open(FILE, "<$verifylog")) { + while(my $string = ) { + logmsg "RUN: $string" if($string !~ /^([ \t]*)$/); + } + close(FILE); + } + } + + my $data; + if(open(FILE, "<$verifyout")) { + while(my $string = ) { + $data .= $string; + } + close(FILE); + } + + if($data && ($data =~ /GNUTLS/) && open(FILE, "<$pidfile")) { + $pid=0+; + close(FILE); + return $pid; + } + elsif($res == 6) { + # curl: (6) Couldn't resolve host '::1' + logmsg "RUN: failed to resolve host (https://$ip:$port/verifiedserver)\n"; + return -1; + } + elsif($data || ($res && ($res != 7))) { + logmsg "RUN: Unknown server on our $server port: $port ($res)\n"; + return -1; + } + return $pid; +} ####################################################################### # STUB for verifying socks @@ -1001,7 +1079,8 @@ my %protofunc = ('http' => \&verifyhttp, 'tftp' => \&verifyftp, 'ssh' => \&verifyssh, 'socks' => \&verifysocks, - 'gopher' => \&verifyhttp); + 'gopher' => \&verifyhttp, + 'http+tls-srp' => \&verifyhttptlssrp); sub verifyserver { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; @@ -1191,6 +1270,87 @@ sub runhttpsserver { return ($httpspid, $pid2); } +####################################################################### +# start the TLS-SRP HTTP server +# +sub runhttptlssrpserver { + my ($verbose) = @_; + my $proto = "http+tls-srp"; + my $ip = $HOSTIP; + my $port = $HTTPTLSSRPPORT; + my $ipvnum = 4; + my $idnum = 1; + my $server; + my $srvrname; + my $pidfile; + my $logfile; + my $flags = ""; + + $server = servername_id($proto, $ipvnum, $idnum); + + $pidfile = $serverpidfile{$server}; + + # don't retry if the server doesn't work + if ($doesntrun{$pidfile}) { + return (0,0); + } + + my $pid = processexists($pidfile); + if($pid > 0) { + stopserver($server, "$pid"); + } + unlink($pidfile) if(-f $pidfile); + + $srvrname = servername_str($proto, $ipvnum, $idnum); + + $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); + + $flags .= "--fork " if($forkserver); + $flags .= "--http "; + $flags .= "-d 1 " if($debugprotocol); + $flags .= "--port $port "; + $flags .= "--srppasswd certs/srp-verifier-db --srppasswdconf certs/srp-verifier-conf "; + $flags .=" >log/gnutls.out 2>&1"; + + # Find gnutls-serv + my $gnutlsserv = find_gnutls_serv(); + if(!$gnutlsserv) { + logmsg "RUN: cannot find gnutls-serv\n"; + return (0,0); + } + my $cmd = "$gnutlsserv $flags"; + my ($httptlssrppid, $pid2) = startnew($cmd, $pidfile, 1, 1); + + if($httptlssrppid <= 0 || !kill(0, $httptlssrppid)) { + # it is NOT alive + logmsg "RUN: failed to start the $srvrname server\n"; + stopserver($server, "$pid2"); + displaylogs($testnumcheck); + $doesntrun{$pidfile} = 1; + return (0,0); + } + + # Server is up. Verify that we can speak to it. + my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); + if(!$pid3) { + logmsg "RUN: $srvrname server failed verification\n"; + # failed to talk to it properly. Kill the server and return failure + stopserver($server, "$httptlssrppid $pid2"); + displaylogs($testnumcheck); + $doesntrun{$pidfile} = 1; + return (0,0); + } + $pid2 = $pid3; + + if($verbose) { + logmsg "RUN: $srvrname server is now running PID $httptlssrppid\n"; + } + + sleep(1); + + return ($httptlssrppid, $pid2); +} + ####################################################################### # start the pingpong server (FTP, POP3, IMAP, SMTP) # @@ -1967,6 +2127,13 @@ sub checksystem { # compiled in because the test will fail. push @protocols, map($_ . "-ipv6", @protocols); + # Hack - we need a different, non-stunnel server to test HTTP + # TLS-SRP, but we don't want to add HTTP+TLS-SRP as a protocol + # throughout curl + if ($has_gnutls) { + push @protocols, ('http+tls-srp'); + } + # 'none' is used in test cases to mean no server push @protocols, ('none'); } @@ -2008,6 +2175,10 @@ sub checksystem { # CharConv enabled $has_charconv=1; } + if($feat =~ /TLS-SRP/i) { + # TLS-SRP enabled + $has_tls_srp=1; + } } } if(!$curl) { @@ -2171,6 +2342,7 @@ sub subVariables { $$thing =~ s/%RTSP6PORT/$RTSP6PORT/g; $$thing =~ s/%GOPHERPORT/$GOPHERPORT/g; $$thing =~ s/%GOPHER6PORT/$GOPHER6PORT/g; + $$thing =~ s/%HTTPTLSSRPPORT/$HTTPTLSSRPPORT/g; # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be # used for time-out tests and that whould work on most hosts as these @@ -2354,6 +2526,11 @@ sub singletest { next; } } + elsif($f eq "TLS-SRP") { + if($has_tls_srp) { + next; + } + } elsif($f eq "socks") { next; } @@ -3257,7 +3434,7 @@ sub startservers { for(@what) { my (@whatlist) = split(/\s+/,$_); my $what = lc($whatlist[0]); - $what =~ s/[^a-z0-9-]//g; + $what =~ s/[^a-z0-9-+]//g; my $certfile; if($what =~ /^(ftp|http|imap|pop3|smtp)s(.*)$/) { @@ -3432,6 +3609,20 @@ sub startservers { $run{'https'}="$pid $pid2"; } } + elsif($what eq "http+tls-srp") { + if(!$has_gnutls) { + return "no GnuTLS"; + } + if(!$run{'http+tls-srp'}) { + ($pid, $pid2) = runhttptlssrpserver($verbose); + if($pid <= 0) { + return "failed starting HTTP+TLS-SRP server (gnutls-serv)"; + } + logmsg sprintf("* pid http+tls-srp => %d %d\n", $pid, $pid2) + if($verbose); + $run{'http+tls-srp'}="$pid $pid2"; + } + } elsif($what eq "tftp") { if(!$run{'tftp'}) { ($pid, $pid2) = runtftpserver("", $verbose); @@ -3522,7 +3713,7 @@ sub serverfortest { my $proto = lc($_); chomp $proto; $proto =~ s/\s.*//g; # take first word - if (! grep /^$proto$/, @protocols) { + if (! grep /^\Q$proto\E$/, @protocols) { if (substr($proto,0,5) ne "socks") { return "curl lacks $proto support"; } @@ -3905,6 +4096,7 @@ $RTSPPORT = $base++; $RTSP6PORT = $base++; $GOPHERPORT =$base++; $GOPHER6PORT=$base++; +$HTTPTLSSRPPORT=$base++; ####################################################################### # clear and create logging directory: diff --git a/tests/serverhelp.pm b/tests/serverhelp.pm index 34b155d0e..faaeebfd0 100644 --- a/tests/serverhelp.pm +++ b/tests/serverhelp.pm @@ -96,7 +96,7 @@ sub servername_str { $proto = uc($proto) if($proto); die "unsupported protocol: $proto" unless($proto && - ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER))$/)); + ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER|HTTP\+TLS-SRP))$/)); $ipver = (not $ipver) ? 'ipv4' : lc($ipver); die "unsupported IP version: $ipver" unless($ipver && diff --git a/tests/sshhelp.pm b/tests/sshhelp.pm index 18de9d3ec..493cbfed8 100644 --- a/tests/sshhelp.pm +++ b/tests/sshhelp.pm @@ -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 @@ -95,6 +95,7 @@ use vars qw( find_sftpsrv find_sftp find_sshkeygen + find_gnutls_serv logmsg sshversioninfo ); @@ -290,6 +291,12 @@ sub find_sfile { return find_file($filename, @spath); } +#*************************************************************************** +# Find gnutls-serv and return canonical filename +# +sub find_gnutls_serv { + return find_file("gnutls-serv", split(':', $ENV{PATH})); +} #*************************************************************************** # Find ssh daemon and return canonical filename