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! */
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
