From 59cf93ccdbaa5e866f9de6b2d9b1ae5cee84863f Mon Sep 17 00:00:00 2001
From: Quinn Slack
Date: Wed, 19 Jan 2011 20:35:02 +0100
Subject: [PATCH] TLS-SRP: support added when using GnuTLS
---
configure.ac | 42 +++++++
include/curl/curl.h | 17 +++
lib/gtls.c | 71 +++++++++++-
lib/strerror.c | 5 +-
lib/url.c | 27 +++++
lib/urldata.h | 14 +++
lib/version.c | 3 +
src/main.c | 50 ++++++++-
tests/FILEFORMAT | 1 +
tests/certs/srp-verifier-conf | 3 +
tests/certs/srp-verifier-db | 2 +
tests/data/Makefile.am | 2 +-
tests/data/test320 | 95 ++++++++++++++++
tests/data/test321 | 33 ++++++
tests/data/test322 | 33 ++++++
tests/data/test323 | 33 ++++++
tests/data/test324 | 33 ++++++
tests/runtests.pl | 200 +++++++++++++++++++++++++++++++++-
tests/serverhelp.pm | 2 +-
tests/sshhelp.pm | 9 +-
20 files changed, 661 insertions(+), 14 deletions(-)
create mode 100644 tests/certs/srp-verifier-conf
create mode 100644 tests/certs/srp-verifier-db
create mode 100644 tests/data/test320
create mode 100644 tests/data/test321
create mode 100644 tests/data/test322
create mode 100644 tests/data/test323
create mode 100644 tests/data/test324
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
+
+
+
+
+
+
+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 |
+Compression | NULL |
+Cipher | AES-128-CBC |
+MAC | SHA1 |
+Ciphersuite | SRP_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
+
+
+
+
+
+
+
+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 |
+Compression | NULL |
+Cipher | AES-128-CBC |
+MAC | SHA1 |
+Ciphersuite | SRP_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