curl-library
Re: Patch for TLS-SRP support (using GnuTLS)
Date: Mon, 20 Dec 2010 04:02:29 -0600
On Dec 18, 2010, at 11:58 AM, Daniel Stenberg wrote:
>> My patch exposes GnuTLS's existing TLS-SRP support to cURL,
> Can you please post it here so that we all can read and review it?
Sure, I just put up the TLS-SRP patch at
http://stanford.edu/~sqs/curl-tls-srp-20101220.patch
and pasted it below. Patch is against 7f3b87d (up-to-date as of Dec 19).
-Quinn
diff --git a/configure.ac b/configure.ac
index ea51689..f65e421 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2801,6 +2801,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$GNUTLS_ENABLED" = "x1"; then
+ SUPPORT_FEATURES="$SUPPORT_FEATURES SRP"
+fi
AC_SUBST(SUPPORT_FEATURES)
diff --git a/include/curl/curl.h b/include/curl/curl.h
index fbd0d9b..d651821 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_SRP_FAILED, /* 89 - Failed SRP auth */
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(TLS_USERNAME, OBJECTPOINT, 204),
+
+ /* Set a password for authenticated TLS */
+ CINIT(TLS_PASSWORD, OBJECTPOINT, 205),
+
+ /* Set authentication type for authenticated TLS */
+ CINIT(TLS_AUTHTYPE, OBJECTPOINT, 206),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -1538,6 +1548,12 @@ enum {
CURL_SSLVERSION_LAST /* never use, keep last */
};
+enum CURL_SSLAUTH {
+ CURL_SSLAUTH_NONE,
+ CURL_SSLAUTH_SRP,
+ CURL_SSLAUTH_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_SRP (1<<14) /* SRP authentication is supported */
/*
* NAME curl_version_info()
diff --git a/lib/gtls.c b/lib/gtls.c
index 845dbbb..fd487a9 100644
--- a/lib/gtls.c
+++ b/lib/gtls.c
@@ -346,6 +346,27 @@ gtls_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
+ if(data->set.ssl.authtype == CURL_SSLAUTH_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_SRP_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_SRP_FAILED;
+ }
+ }
+
if(data->set.ssl.CAfile) {
/* set the trusted CA cert bundle file */
gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
@@ -432,8 +453,16 @@ gtls_connect_step1(struct connectdata *conn,
}
/* 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_SSLAUTH_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 {
+ 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,
@@ -495,8 +524,18 @@ 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;
+
+ if(data->set.ssl.authtype == CURL_SSLAUTH_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 {
+ failf(data, "failed to get server cert");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
}
infof(data, "\t common name: WARNING couldn't obtain\n");
}
@@ -529,8 +568,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);
@@ -660,6 +701,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 */
@@ -813,6 +856,10 @@ static void close_one(struct connectdata *conn,
gnutls_certificate_free_credentials(conn->ssl[idx].cred);
conn->ssl[idx].cred = NULL;
}
+ 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;
+ }
}
void Curl_gtls_close(struct connectdata *conn, int sockindex)
@@ -881,6 +928,9 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
gnutls_deinit(conn->ssl[sockindex].session);
}
gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+ if(data->set.ssl.authtype == CURL_SSLAUTH_SRP
+ && data->set.ssl.username != NULL)
+ gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
conn->ssl[sockindex].cred = NULL;
conn->ssl[sockindex].session = NULL;
diff --git a/lib/url.c b/lib/url.c
index 95d024d..02a5349 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -751,6 +751,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
*/
set->ssl.verifypeer = TRUE;
set->ssl.verifyhost = 2;
+ set->ssl.authtype = CURL_SSLAUTH_NONE;
set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
type */
set->ssl.sessionid = TRUE; /* session ID caching enabled by default */
@@ -2526,6 +2527,24 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_FNMATCH_DATA:
data->set.fnmatch_data = va_arg(param, void *);
break;
+ case CURLOPT_TLS_USERNAME:
+ result = setstropt(&data->set.str[STRING_TLS_USERNAME],
+ va_arg(param, char *));
+ if (data->set.str[STRING_TLS_USERNAME] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_SSLAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLS_PASSWORD:
+ result = setstropt(&data->set.str[STRING_TLS_PASSWORD],
+ va_arg(param, char *));
+ if (data->set.str[STRING_TLS_USERNAME] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_SSLAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLS_AUTHTYPE:
+ if (strncmp((char *)va_arg(param, char *), "SRP", strlen("SRP")) == 0)
+ data->set.ssl.authtype = CURL_SSLAUTH_SRP;
+ else
+ data->set.ssl.authtype = CURL_SSLAUTH_NONE;
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_FAILED_INIT; /* correct this */
@@ -4905,6 +4924,8 @@ 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];
+ data->set.ssl.username = data->set.str[STRING_TLS_USERNAME];
+ data->set.ssl.password = data->set.str[STRING_TLS_PASSWORD];
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 208ff4e..0d6fbaf 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -251,6 +251,7 @@ struct ssl_connect_data {
#ifdef USE_GNUTLS
gnutls_session session;
gnutls_certificate_credentials cred;
+ gnutls_srp_client_credentials srp_client_cred;
ssl_connect_state connecting_state;
#endif /* USE_GNUTLS */
#ifdef USE_POLARSSL
@@ -300,6 +301,10 @@ struct ssl_config_data {
void *fsslctxp; /* parameter for call back */
bool sessionid; /* cache session IDs or not */
bool certinfo; /* gather lots of certificate info */
+
+ char *username; /* TLS username (for, e.g., SRP) */
+ char *password; /* TLS password (for, e.g., SRP) */
+ enum CURL_SSLAUTH authtype; /* TLS authentication type (default SRP) */
};
/* information stored about one single SSL session */
@@ -1294,6 +1299,9 @@ enum dupstring {
#endif
STRING_MAIL_FROM,
+ STRING_TLS_USERNAME, /* TLS auth <username> */
+ STRING_TLS_PASSWORD, /* TLS auth <password> */
+
/* -- end of strings -- */
STRING_LAST /* not used, just an end-of-list marker */
};
diff --git a/lib/version.c b/lib/version.c
index 9ba2e33..40b48ed 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -260,6 +260,9 @@ static curl_version_info_data version_info = {
#if defined(CURL_DOES_CONVERSIONS)
| CURL_VERSION_CONV
#endif
+#if defined(USE_GNUTLS)
+ | CURL_VERSION_SRP
+#endif
,
NULL, /* ssl_version */
0, /* ssl_version_num, this is kept at zero */
diff --git a/src/main.c b/src/main.c
index a38ad62..b6c57e9 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,9 @@ static void help(void)
" --url <URL> Set URL to work with",
" -B/--use-ascii Use ASCII/text transfer",
" -u/--user <user[:password]> Set server user and password",
+ " --tlsuser <user> Set TLS username",
+ " --tlspassword <string> Set TLS password",
+ " --tlsauthtype <string> Set TLS authentication type (default SRP)",
" -A/--user-agent <string> User-Agent to send to server (H)",
" -v/--verbose Make the operation more talkative",
" -V/--version Show version number and quit",
@@ -1916,6 +1922,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"Eh","pubkey", TRUE},
{"Ei", "hostpubmd5", TRUE},
{"Ej","crlfile", TRUE},
+ {"Ek","tlsuser", TRUE},
+ {"El","tlspassword", TRUE},
+ {"Em","tlsauthtype", TRUE},
{"f", "fail", FALSE},
{"F", "form", TRUE},
{"Fs","form-string", TRUE},
@@ -2742,6 +2751,26 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
/* CRL file */
GetStr(&config->crlfile, nextarg);
break;
+ case 'k': /* TLS username */
+ if(curlinfo->features & CURL_VERSION_SRP) {
+ GetStr(&config->tls_username, nextarg);
+ } else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'l': /* TLS password */
+ if(curlinfo->features & CURL_VERSION_SRP) {
+ GetStr(&config->tls_password, nextarg);
+ } else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'm': /* TLS authentication type */
+ if(curlinfo->features & CURL_VERSION_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;
default: /* certificate file */
{
char *ptr = strchr(nextarg, ':');
@@ -3120,7 +3149,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},
+ {"SRP", CURL_VERSION_SRP}
};
printf("Features: ");
for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
@@ -5460,6 +5490,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_TLS_USERNAME, config->tls_username);
+ curl_easy_setopt(curl, CURLOPT_TLS_PASSWORD, config->tls_password);
+
retry_numretries = config->req_retry;
retrystart = cutil_tvnow();
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2010-12-20