Hi,

Recently I added a HKPS pool to sks-keyservers.net, and in that process
I'm validating the SKS keyservers SSL/TLS certificates versus my own
Certificate Authority, so only servers with certificates signed by
myself are included. This ensure a subjectAltName for the appropriate
host, in order to avoid certificate failures. So far so good.

Some servers for various reasons need to have another certificate
installed signed by another authority. In order for this to be handled
properly, Server Name Indication is used to properly map the request
with the virtual host and the certificate to present to the client.

My crawler use curl as the basis for the requests, and as I connect
using the hostname found in server-discovery, whereby I need it to be
valid for the purpose of a DNS Round Robin, it use the HTTP Host: header
matching the keyserver pool. The issue with vanilla curl, is however,
that there is no way to manually set the SNI hostname to use, and it
will default to the hostname of the request.

As such I have created a (very) crude patch that will use the Host
header presented instead. Based on a patch I found in the curl mailing
list archives[0, 1] and rebased it to the current 7.2x version (lastly
applied to 7.28).

I'm including it here in case it is useful for anyone else, and to add
my request that the feature can hopefully be implemented in the
mainline. I say it is crude due to e.g. a verbatim copy of
copy_header_value() from http.c, as for my purpose I didn't want to make
too many changes to the overall curl, and simply exposing this in http.h
results in build errors.

Otherwise I'll keep maintaining my patchset locally.

Brgds,

[0] http://curl.haxx.se/mail/lib-2008-07/0300.html
[1] http://curl.haxx.se/mail/lib-2010-08/0166.html

-- 
----------------------------
Kristian Fiskerstrand
http://www.sumptuouscapital.com
Twitter: @krifisk
----------------------------
"A government that robs Peter to pay Paul can always depend on the
support of Paul."
(George Bernard Shaw)
----------------------------
This email was digitally signed using the OpenPGP
standard. If you want to read more about this
The book: Sending Emails - The Safe Way: An
introduction to OpenPGP security is
available in both Amazon Kindle and Paperback
format at
http://www.amazon.com/dp/B006RSG1S4/
----------------------------
Public PGP key 0xE3EDFAE3 at http://www.sumptuouscapital.com/pgp/
diff -r 5269aeca0252 lib/http.h
--- a/lib/http.h	Tue Oct 09 19:49:42 2012 +0200
+++ b/lib/http.h	Tue Oct 09 20:23:53 2012 +0200
@@ -30,6 +30,7 @@
 extern const struct Curl_handler Curl_handler_https;
 #endif
 
+
 bool Curl_compareheader(const char *headerline,  /* line to check */
                         const char *header,   /* header keyword _with_ colon */
                         const char *content); /* content string to find */
diff -r 5269aeca0252 lib/ssluse.c
--- a/lib/ssluse.c	Tue Oct 09 19:49:42 2012 +0200
+++ b/lib/ssluse.c	Tue Oct 09 20:23:53 2012 +0200
@@ -145,6 +145,61 @@
 static char global_passwd[64];
 #endif
 
+/*
+ * Strip off leading and trailing whitespace from the value in the
+ * given HTTP header line and return a strdupped copy. Returns NULL in
+ * case of allocation failure. Returns an empty string if the header value
+ * consists entirely of whitespace.
+ */
+static char *copy_header_value(const char *h)
+{
+  const char *start;
+  const char *end;
+  char *value;
+  size_t len;
+
+  DEBUGASSERT(h);
+
+  /* Find the end of the header name */
+  while(*h && (*h != ':'))
+    ++h;
+
+  if(*h)
+    /* Skip over colon */
+    ++h;
+
+  /* Find the first non-space letter */
+  start = h;
+  while(*start && ISSPACE(*start))
+    start++;
+
+  /* data is in the host encoding so
+     use '\r' and '\n' instead of 0x0d and 0x0a */
+  end = strchr(start, '\r');
+  if(!end)
+    end = strchr(start, '\n');
+  if(!end)
+    end = strchr(start, '\0');
+  if(!end)
+    return NULL;
+
+  /* skip all trailing space letters */
+  while((end > start) && ISSPACE(*end))
+    end--;
+
+  /* get length of the type */
+  len = end-start+1;
+
+  value = malloc(len + 1);
+  if(!value)
+    return NULL;
+
+  memcpy(value, start, len);
+  value[len] = 0; /* zero terminate */
+
+  return value;
+}
+
 static int passwd_callback(char *buf, int num, int encrypting
 #ifdef HAVE_USERDATA_IN_PWD_CALLBACK
                            /* This was introduced in 0.9.4, we can set this
@@ -1447,6 +1502,8 @@
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   long ctx_options;
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  const char *hostname;
+  bool hostname_static;
   bool sni;
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
@@ -1734,14 +1791,28 @@
   connssl->server_cert = 0x0;
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  hostname = Curl_checkheaders(data, "Host:");
+  if(hostname && (!data->state.this_is_a_follow ||
+                  Curl_raw_equal(data->state.first_host, conn->host.name))) {
+    hostname_static = FALSE;
+    hostname = copy_header_value(hostname);
+    if(!hostname) {
+      return CURLE_OUT_OF_MEMORY;
+    }
+  } else {
+    hostname_static = TRUE;
+    hostname = conn->host.name;
+  }
   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
      sni &&
-     !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
+     !SSL_set_tlsext_host_name(connssl->handle, hostname))
     infof(data, "WARNING: failed to configure server name indication (SNI) "
           "TLS extension\n");
+     if(!hostname_static)
+        free((char *) hostname);
 #endif
 
   /* Check if there's a cached ID we can/should use here! */

Attachment: signature.asc
Description: OpenPGP digital signature

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to