On Dec 21, 2010, at 6:12 AM, Daniel Stenberg wrote:

> We're talking about adding support for TLS authentication, using the specific
> auth type SRP, right? SRP is a concept that is not specificly bound to TLS.

Yes, good point.

> Also, I figure there's a probability that we will add support for more/other
> types in the future.
> 
>> +if test "x$GNUTLS_ENABLED" = "x1"; then
>> +  SUPPORT_FEATURES="$SUPPORT_FEATURES SRP"
>> +fi
> 
> ... so I think this is either better called TLS-SRP or possibly without
> specifying the type just "TLSAUTH" or something.
> 
>> +  CURLE_SRP_FAILED,              /* 89 - Failed SRP auth */
>> +#define CURL_VERSION_SRP       (1<<14) /* SRP authentication is supported */
> 
> ... and these feel like they are for TLSAUTH that failed and the bit would
> be for TLASAUTH.

OK, the configure.ac feature is now "TLS-SRP", the options are 
CURLOPT_TLSAUTH_*, the version is CURL_VERSION_TLSAUTH_SRP,
and the error is CURLE_TLSAUTH_FAILED. Updated patch pasted below
and at:
  http://stanford.edu/~sqs/curl-tls-srp-20101224.patch

> BTW, does this TLSAUTH and SRP stuff depend on some particular
> GnuTLS version? Our currently set "goal" is to work with GnuTLS 1.2.

It doesn't work with GnuTLS 1.2, unfortunately. GnuTLS 2.0.1 (2007-09-20)
changed the SRP cipher suite values to the official IANA-assigned values, which 
completely broke backwards compatibility. It definitely works with GnuTLS 2.3
releases (I tried 2.3.5, 2008-04-14, gnutls git 8460e8a3). The earliest release
it works with is probably 2.2.0 (2007-12-14); I can figure out for sure in a 
week 
or so. Want me to add a check for a minimum GnuTLS version before enabling
TLS-SRP in configure.ac?

I'll also work on some tests (will have to figure out how to get stunnel working
with TLS-SRP).

-Quinn


diff --git a/configure.ac b/configure.ac
index ea51689..58649a2 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 TLS-SRP"
+fi
 
 AC_SUBST(SUPPORT_FEATURES)
 
diff --git a/include/curl/curl.h b/include/curl/curl.h
index fbd0d9b..bf65420 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 845dbbb..8527c7b 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_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;
+    }
+  }
+
   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_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 {
+    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_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 {
+        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_TLSAUTH_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..457cd18 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_TLSAUTH_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_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;
   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_TLSAUTH_USERNAME];
+  data->set.ssl.password = data->set.str[STRING_TLSAUTH_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..fc5011c 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_TLSAUTH authtype; /* TLS authentication type (default SRP) */
 };
 
 /* information stored about one single SSL session */
@@ -1294,6 +1299,9 @@ enum dupstring {
 #endif
   STRING_MAIL_FROM,
 
+  STRING_TLSAUTH_USERNAME,     /* TLS auth <username> */
+  STRING_TLSAUTH_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..6d665fa 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_TLSAUTH_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..529a042 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_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;
       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},
+          {"TLS-SRP", CURL_VERSION_TLSAUTH_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_TLSAUTH_USERNAME, config->tls_username);
+        curl_easy_setopt(curl, CURLOPT_TLSAUTH_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

Reply via email to