Re: [squid-users] [PATCH]: hardware SSL acceleration support for squid

From: Henrik Nordstrom <hno@dont-contact.us>
Date: 20 Nov 2002 19:08:14 +0100

Many thanks for your patch.

Your patch will be included in the next SSL update.

 * Client certificate support
 * Client certificate acl support via external_acl
 * Backend SSL support
 * https:// gatewaying for proxy clients not supporting SSL
 * Some minor bug fixes in OpenSSL socket interactions

and now

 * Hardware SSL accelerator support

Attached to this message you can find a preliminary version of this SSL
support update including your ssl_engine directive. This patch is
relative to the current Squid-2.5 snapshots. Please verify that the
patch got merged correcly.

Regards
Henrik Nordström

ons 2002-11-20 klockan 15.23 skrev Gianni Tedesco:
> Hi,
>
> We have recently been using squid 2.5 as an SSL accelerator. The
> attached patch allows you to do this using specialised SSL hardware.
>
> It adds a new config 'ssl_engine' which is a string to pass to the
> OpenSSL library telling it what engine (which is usually hardware) to
> use.
>
> I hope someone will find it useful.
>
> --
> // Gianni Tedesco (gianni at ecsc dot co dot uk)
> lynx --source www.scaramanga.co.uk/gianni-at-ecsc.asc | gpg --import
> 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
> ----
>

> diff -urN squid-2.5.STABLE1.orig/configure squid-2.5.STABLE1/configure
> --- squid-2.5.STABLE1.orig/configure Tue Sep 24 21:00:03 2002
> +++ squid-2.5.STABLE1/configure Wed Nov 20 11:49:19 2002
> @@ -3727,6 +3727,7 @@
> openssl/err.h \
> openssl/md5.h \
> openssl/ssl.h \
> + openssl/engine.h \
> poll.h \
> pwd.h \
> regex.h \
> diff -urN squid-2.5.STABLE1.orig/configure.in squid-2.5.STABLE1/configure.in
> --- squid-2.5.STABLE1.orig/configure.in Tue Sep 24 21:00:03 2002
> +++ squid-2.5.STABLE1/configure.in Wed Nov 20 11:48:18 2002
> @@ -1170,6 +1170,7 @@
> openssl/err.h \
> openssl/md5.h \
> openssl/ssl.h \
> + openssl/engine.h \
> poll.h \
> pwd.h \
> regex.h \
> diff -urN squid-2.5.STABLE1.orig/include/autoconf.h.in squid-2.5.STABLE1/include/autoconf.h.in
> --- squid-2.5.STABLE1.orig/include/autoconf.h.in Mon Jul 15 22:29:47 2002
> +++ squid-2.5.STABLE1/include/autoconf.h.in Wed Nov 20 11:48:57 2002
> @@ -705,6 +705,9 @@
> /* Define if you have the <openssl/ssl.h> header file. */
> #undef HAVE_OPENSSL_SSL_H
>
> +/* Define if you have the <openssl/engine.h> header file. */
> +#undef HAVE_OPENSSL_ENGINE_H
> +
> /* Define if you have the <poll.h> header file. */
> #undef HAVE_POLL_H
>
> diff -urN squid-2.5.STABLE1.orig/src/cf.data.pre squid-2.5.STABLE1/src/cf.data.pre
> --- squid-2.5.STABLE1.orig/src/cf.data.pre Wed Nov 20 10:33:12 2002
> +++ squid-2.5.STABLE1/src/cf.data.pre Wed Nov 20 11:48:18 2002
> @@ -143,6 +143,15 @@
> messages.
> DOC_END
>
> +NAME: ssl_engine
> +TYPE: string
> +LOC: Config.SSL.ssl_engine
> +DEFAULT: none
> +DOC_START
> + The openssl engine to use. You will need to set this if you
> + would like to use hardware SSL acceleration for example.
> +DOC_END
> +
> NAME: icp_port udp_port
> TYPE: ushort
> DEFAULT: 3130
> diff -urN squid-2.5.STABLE1.orig/src/ssl_support.c squid-2.5.STABLE1/src/ssl_support.c
> --- squid-2.5.STABLE1.orig/src/ssl_support.c Sun Jul 21 01:30:02 2002
> +++ squid-2.5.STABLE1/src/ssl_support.c Wed Nov 20 11:48:18 2002
> @@ -236,6 +236,23 @@
> ssl_initialized = 1;
> SSL_load_error_strings();
> SSLeay_add_ssl_algorithms();
> +#ifdef HAVE_OPENSSL_ENGINE_H
> + if ( Config.SSL.ssl_engine ) {
> + ENGINE *e;
> + if ( !(e = ENGINE_by_id(Config.SSL.ssl_engine)) ) {
> + fatalf("Unable to find SSL engine '%s'\n", Config.SSL.ssl_engine);
> + }
> + if ( !ENGINE_set_default(e,ENGINE_METHOD_ALL) ) {
> + ssl_error = ERR_get_error();
> + fatalf("Failed to initialise SSL engine: %s\n",
> + ERR_error_string(ssl_error, NULL));
> + }
> + }
> +#else
> + if ( Config.SSL.ssl_engine ) {
> + fatalf("Your OpenSSL has no SSL engine support\n");
> + }
> +#endif
> }
> if (!keyfile)
> keyfile = certfile;
> diff -urN squid-2.5.STABLE1.orig/src/ssl_support.h squid-2.5.STABLE1/src/ssl_support.h
> --- squid-2.5.STABLE1.orig/src/ssl_support.h Fri Oct 19 23:34:49 2001
> +++ squid-2.5.STABLE1/src/ssl_support.h Wed Nov 20 11:48:18 2002
> @@ -42,6 +42,9 @@
> #if HAVE_OPENSSL_ERR_H
> #include <openssl/err.h>
> #endif
> +#if HAVE_OPENSSL_ENGINE_H
> +#include <openssl/engine.h>
> +#endif
>
> SSL_CTX *sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options);
> int ssl_read_method(int, char *, int);
> diff -urN squid-2.5.STABLE1.orig/src/structs.h squid-2.5.STABLE1/src/structs.h
> --- squid-2.5.STABLE1.orig/src/structs.h Wed Nov 20 10:33:12 2002
> +++ squid-2.5.STABLE1/src/structs.h Wed Nov 20 11:48:18 2002
> @@ -675,6 +675,7 @@
> #if USE_SSL
> struct {
> int unclean_shutdown;
> + char *ssl_engine;
> } SSL;
> #endif
> wordlist *ext_methods;

Patch file generated ons nov 20 19:01:02 CET 2002 from
CVS branch ssl
CVS base branch s2_5
CVS repository: filer:/cvsroot
CVS module: squid

cvs -q rdiff -u -kk -r Z-ssl_merge_s2_5 -r ssl squid
Index: squid/configure.in
diff -u squid/configure.in:1.1.2.9 squid/configure.in:1.1.2.2.2.5
--- squid/configure.in:1.1.2.9 Tue Oct 22 10:37:16 2002
+++ squid/configure.in Wed Nov 20 19:00:13 2002
@@ -1144,6 +1144,7 @@
         openssl/err.h \
         openssl/md5.h \
         openssl/ssl.h \
+ openssl/engine.h \
         poll.h \
         pwd.h \
         regex.h \
Index: squid/src/HttpHeader.c
diff -u squid/src/HttpHeader.c:1.1.2.1 squid/src/HttpHeader.c:1.1.2.1.2.1
--- squid/src/HttpHeader.c:1.1.2.1 Mon Aug 12 19:17:18 2002
+++ squid/src/HttpHeader.c Mon Nov 11 22:38:18 2002
@@ -129,6 +129,7 @@
 #if X_ACCELERATOR_VARY
     {"X-Accelerator-Vary", HDR_X_ACCELERATOR_VARY, ftStr},
 #endif
+ {"Front-End-Https", HDR_FRONT_END_HTTPS, ftStr},
     {"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */
 };
 static HttpHeaderFieldInfo *Headers = NULL;
Index: squid/src/access_log.c
diff -u squid/src/access_log.c:1.1.2.1 squid/src/access_log.c:1.1.2.1.2.2
--- squid/src/access_log.c:1.1.2.1 Mon Aug 12 19:17:19 2002
+++ squid/src/access_log.c Sat Aug 24 02:55:10 2002
@@ -235,13 +235,20 @@
 accessLogSquid(AccessLogEntry * al)
 {
     const char *client = NULL;
- char *user = NULL;
+ const char *user = NULL;
     if (Config.onoff.log_fqdn)
         client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
     if (client == NULL)
         client = inet_ntoa(al->cache.caddr);
- user = accessLogFormatName(al->cache.authuser ?
- al->cache.authuser : al->cache.rfc931);
+ user = accessLogFormatName(al->cache.authuser);
+#if USE_SSL
+ if (!user)
+ user = accessLogFormatName(al->cache.ssluser);
+#endif
+ if (!user)
+ user = accessLogFormatName(al->cache.rfc931);
+ if (user && !*user)
+ safe_free(user);
     logfilePrintf(logfile, "%9d.%03d %6d %s %s/%03d %ld %s %s %s %s%s/%s %s",
         (int) current_time.tv_sec,
         (int) current_time.tv_usec / 1000,
@@ -252,7 +259,7 @@
         (long int) al->cache.size,
         al->private.method_str,
         al->url,
- user && *user ? user : dash_str,
+ user ? user : dash_str,
         al->hier.ping.timedout ? "TIMEOUT_" : "",
         hier_strings[al->hier.code],
         al->hier.host,
Index: squid/src/acl.c
diff -u squid/src/acl.c:1.1.2.6 squid/src/acl.c:1.1.2.1.2.9
--- squid/src/acl.c:1.1.2.6 Mon Nov 11 18:41:03 2002
+++ squid/src/acl.c Mon Nov 11 18:44:21 2002
@@ -101,6 +101,14 @@
 static SPLAYCMP aclArpCompare;
 static SPLAYWALKEE aclDumpArpListWalkee;
 #endif
+#if USE_SSL
+static void aclParseCertList(void *curlist);
+static int aclMatchUserCert(void *data, aclCheck_t *);
+static int aclMatchCACert(void *data, aclCheck_t *);
+static wordlist *aclDumpCertList(void *data);
+static void aclDestroyCertList(void *data);
+#endif
+
 static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char *MatchParam);
 
 static squid_acl
@@ -178,6 +186,12 @@
         return ACL_MAX_USER_IP;
     if (!strcmp(s, "external"))
         return ACL_EXTERNAL;
+#if USE_SSL
+ if (!strcmp(s, "user_cert"))
+ return ACL_USER_CERT;
+ if (!strcmp(s, "ca_cert"))
+ return ACL_CA_CERT;
+#endif
     return ACL_NONE;
 }
 
@@ -252,6 +266,12 @@
         return "max_user_ip";
     if (type == ACL_EXTERNAL)
         return "external";
+#if USE_SSL
+ if (type == ACL_USER_CERT)
+ return "user_cert";
+ if (type == ACL_CA_CERT)
+ return "ca_cert";
+#endif
     return "ERROR";
 }
 
@@ -672,6 +692,91 @@
     }
 }
 
+#if USE_SSL
+static void
+aclParseCertList(void *curlist)
+{
+ acl_cert_data **datap = curlist;
+ splayNode **Top;
+ char *t;
+ char *attribute = strtokFile();
+ if (!attribute)
+ self_destruct();
+ if (*datap) {
+ if (strcasecmp((*datap)->attribute, attribute) != 0)
+ self_destruct();
+ } else {
+ *datap = memAllocate(MEM_ACL_DENY_INFO_LIST);
+ (*datap)->attribute = xstrdup(attribute);
+ }
+ Top = &(*datap)->values;
+ while ((t = strtokFile())) {
+ *Top = splay_insert(xstrdup(t), *Top, aclDomainCompare);
+ }
+}
+
+static int
+aclMatchUserCert(void *data, aclCheck_t * checklist)
+{
+ acl_cert_data *cert_data = data;
+ const char *value;
+ SSL *ssl = fd_table[checklist->conn->fd].ssl;
+
+ if (!ssl)
+ return 0;
+ value = sslGetUserAttribute(ssl, cert_data->attribute);
+ if (!value)
+ return 0;
+ cert_data->values = splay_splay(value, cert_data->values, (SPLAYCMP *) strcmp);
+ return !splayLastResult;
+}
+
+static int
+aclMatchCACert(void *data, aclCheck_t * checklist)
+{
+ acl_cert_data *cert_data = data;
+ const char *value;
+ SSL *ssl = fd_table[checklist->conn->fd].ssl;
+
+ if (!ssl)
+ return 0;
+ value = sslGetCAAttribute(ssl, cert_data->attribute);
+ if (!value)
+ return 0;
+ cert_data->values = splay_splay(value, cert_data->values, (SPLAYCMP *) strcmp);
+ return !splayLastResult;
+}
+
+static void
+aclDestroyCertList(void *curlist)
+{
+ acl_cert_data **datap = curlist;
+ if (!*datap)
+ return;
+ splay_destroy((*datap)->values, xfree);
+ memFree(*datap, MEM_ACL_CERT_DATA);
+ *datap = NULL;
+}
+
+static void
+aclDumpCertListWalkee(void *node_data, void *outlist)
+{
+ /* outlist is really a wordlist ** */
+ wordlistAdd(outlist, node_data);
+}
+
+static wordlist *
+aclDumpCertList(void *curlist)
+{
+ acl_cert_data *data = curlist;
+ wordlist *wl = NULL;
+ wordlistAdd(&wl, data->attribute);
+ if (data->values)
+ splay_walk(data->values, aclDumpCertListWalkee, &wl);
+ return wl;
+}
+#endif
+
 void
 aclParseAclLine(acl ** head)
 {
@@ -812,6 +917,12 @@
     case ACL_EXTERNAL:
         aclParseExternal(&A->data);
         break;
+#if USE_SSL
+ case ACL_USER_CERT:
+ case ACL_CA_CERT:
+ aclParseCertList(&A->data);
+ break;
+#endif
     case ACL_NONE:
     case ACL_ENUM_MAX:
         fatal("Bad ACL type");
@@ -1676,6 +1787,14 @@
     case ACL_EXTERNAL:
         return aclMatchExternal(ae->data, checklist);
         /* NOTREACHED */
+#if USE_SSL
+ case ACL_USER_CERT:
+ return aclMatchUserCert(ae->data, checklist);
+ /* NOTREACHED */
+ case ACL_CA_CERT:
+ return aclMatchCACert(ae->data, checklist);
+ /* NOTREACHED */
+#endif
     case ACL_NONE:
     case ACL_ENUM_MAX:
         break;
@@ -2120,6 +2239,12 @@
         case ACL_EXTERNAL:
             aclDestroyExternal(&a->data);
             break;
+#if USE_SSL
+ case ACL_USER_CERT:
+ case ACL_CA_CERT:
+ aclDestroyCertList(&a->data);
+ break;
+#endif
         case ACL_NONE:
         case ACL_ENUM_MAX:
             debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type);
@@ -2533,6 +2658,11 @@
 #endif
     case ACL_EXTERNAL:
         return aclDumpExternal(a->data);
+#if USE_SSL
+ case ACL_USER_CERT:
+ case ACL_CA_CERT:
+ return aclDumpCertList(a->data);
+#endif
     case ACL_NONE:
     case ACL_ENUM_MAX:
         break;
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.1.2.6 squid/src/cache_cf.c:1.1.2.1.2.14
--- squid/src/cache_cf.c:1.1.2.6 Fri Nov 15 04:15:02 2002
+++ squid/src/cache_cf.c Wed Nov 20 19:00:39 2002
@@ -433,6 +433,9 @@
             debug(22, 0) ("WARNING: 'maxconn' ACL (%s) won't work with client_db disabled\n", a->name);
         }
     }
+#if USE_SSL
+ Config.ssl_client.sslContext = sslCreateClientContext(Config.ssl_client.cert, Config.ssl_client.key, Config.ssl_client.version, Config.ssl_client.cipher, Config.ssl_client.options, Config.ssl_client.flags, Config.ssl_client.cafile, Config.ssl_client.capath);
+#endif
 }
 
 /* Parse a time specification from the config file. Store the
@@ -1465,6 +1468,42 @@
             p->options.allow_miss = 1;
         } else if (!strncasecmp(token, "max-conn=", 9)) {
             p->max_conn = atoi(token + 9);
+#if USE_SSL
+ } else if (strcmp(token, "ssl") == 0) {
+ p->use_ssl = 1;
+ } else if (strncmp(token, "sslcert=", 8) == 0) {
+ safe_free(p->sslcert);
+ p->sslcert = xstrdup(token + 8);
+ } else if (strncmp(token, "sslkey=", 7) == 0) {
+ safe_free(p->sslkey);
+ p->sslkey = xstrdup(token + 7);
+ } else if (strncmp(token, "sslversion=", 11) == 0) {
+ p->sslversion = atoi(token + 11);
+ } else if (strncmp(token, "ssloptions=", 11) == 0) {
+ safe_free(p->ssloptions);
+ p->ssloptions = xstrdup(token + 11);
+ } else if (strncmp(token, "sslcipher=", 10) == 0) {
+ safe_free(p->sslcipher);
+ p->sslcipher = xstrdup(token + 10);
+ } else if (strncmp(token, "sslcafile=", 10) == 0) {
+ safe_free(p->sslcafile);
+ p->sslcipher = xstrdup(token + 10);
+ } else if (strncmp(token, "sslcapath=", 10) == 0) {
+ safe_free(p->sslcapath);
+ p->sslcipher = xstrdup(token + 10);
+ } else if (strncmp(token, "sslflags=", 9) == 0) {
+ safe_free(p->sslflags);
+ p->sslflags = xstrdup(token + 9);
+ } else if (strncmp(token, "ssldomain=", 10) == 0) {
+ safe_free(p->ssldomain);
+ p->ssldomain = xstrdup(token + 10);
+#endif
+ } else if (strcmp(token, "front-end-https") == 0) {
+ p->front_end_https = 1;
+ } else if (strcmp(token, "front-end-https=on") == 0) {
+ p->front_end_https = 1;
+ } else if (strcmp(token, "front-end-https=auto") == 0) {
+ p->front_end_https = 2;
         } else {
             debug(3, 0) ("parse_peer: token='%s'\n", token);
             self_destruct();
@@ -1492,6 +1531,11 @@
         cbdataLock(p->digest); /* so we know when/if digest disappears */
     }
 #endif
+#if USE_SSL
+ if (p->use_ssl) {
+ p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath);
+ }
+#endif
     while (*head != NULL)
         head = &(*head)->next;
     *head = p;
@@ -2330,12 +2374,25 @@
         } else if (strncmp(token, "cipher=", 7) == 0) {
             safe_free(s->cipher);
             s->cipher = xstrdup(token + 7);
+ } else if (strncmp(token, "clientca=", 9) == 0) {
+ safe_free(s->clientca);
+ s->clientca = xstrdup(token + 9);
+ } else if (strncmp(token, "cafile=", 7) == 0) {
+ safe_free(s->cafile);
+ s->cafile = xstrdup(token + 7);
+ } else if (strncmp(token, "capath=", 7) == 0) {
+ safe_free(s->capath);
+ s->capath = xstrdup(token + 7);
+ } else if (strncmp(token, "sslflags=", 9) == 0) {
+ safe_free(s->sslflags);
+ s->sslflags = xstrdup(token + 9);
         } else {
             self_destruct();
         }
     }
     while (*head)
         head = &(*head)->next;
+ s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath);
     *head = s;
 }
 
@@ -2343,18 +2400,26 @@
 dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
 {
     while (s) {
- storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"",
+ storeAppendPrintf(e, "%s %s:%d",
             n,
             inet_ntoa(s->s.sin_addr),
- ntohs(s->s.sin_port),
- s->cert,
- s->key);
+ ntohs(s->s.sin_port));
+ if (s->cert)
+ storeAppendPrintf(e, " cert=%s", s->cert);
+ if (s->key)
+ storeAppendPrintf(e, " key=%s", s->cert);
         if (s->version)
             storeAppendPrintf(e, " version=%d", s->version);
         if (s->options)
             storeAppendPrintf(e, " options=%s", s->options);
         if (s->cipher)
             storeAppendPrintf(e, " cipher=%s", s->cipher);
+ if (s->cafile)
+ storeAppendPrintf(e, " cafile=%s", s->cafile);
+ if (s->capath)
+ storeAppendPrintf(e, " capath=%s", s->capath);
+ if (s->sslflags)
+ storeAppendPrintf(e, " sslflags=%s", s->sslflags);
         storeAppendPrintf(e, "\n");
         s = s->next;
     }
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.1.2.10 squid/src/cf.data.pre:1.1.2.1.2.16
--- squid/src/cf.data.pre:1.1.2.10 Mon Nov 11 18:41:03 2002
+++ squid/src/cf.data.pre Wed Nov 20 19:00:13 2002
@@ -131,6 +131,26 @@
                             NO_TLSv1 Disallow the use of TLSv1
                         See src/ssl_support.c or OpenSSL documentation
                         for a more complete list.
+
+ clientca= File containing the list of CAs to use when
+ requesting a client certificate
+
+ cafile= File containing additional CA certificates to
+ use when verifying client certificates. If unset
+ clientca will be used.
+
+ capath= Directory containing additional CA certificates
+ to use when verifying client certificates
+
+ sslflags= Various flags modifying the use of SSL:
+ DELAYED_AUTH
+ Don't request client certificates
+ immediately, but wait until acl processing
+ requires a certificate
+ NO_DEFAULT_CA
+ Don't use the default CA list built in
+ to OpenSSL.
+
 DOC_END
 
 NAME: ssl_unclean_shutdown
@@ -143,6 +163,84 @@
         messages.
 DOC_END
 
+NAME: ssl_engine
+TYPE: string
+LOC: Config.SSL.ssl_engine
+DEFAULT: none
+DOC_START
+ The openssl engine to use. You will need to set this if you
+ would like to use hardware SSL acceleration for example.
+DOC_END
+
+NAME: sslproxy_client_certificate
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cert
+TYPE: string
+DOC_START
+ Client SSL Certificate to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_client_key
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.key
+TYPE: string
+DOC_START
+ Client SSL Key to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_version
+IFDEF: USE_SSL
+DEFAULT: 1
+LOC: Config.ssl_client.version
+TYPE: int
+DOC_START
+ SSL version level to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_options
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.options
+TYPE: string
+DOC_START
+ SSL engine options to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_cipher
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cipher
+TYPE: string
+DOC_START
+ SSL cipher list to use when proxying https:// URLs
+DOC_END
+
+NAME: sslproxy_cafile
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.cafile
+TYPE: string
+DOC_START
+DOC_END
+
+NAME: sslproxy_capath
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.capath
+TYPE: string
+DOC_START
+DOC_END
+
+NAME: sslproxy_flags
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.flags
+TYPE: string
+DOC_START
+DOC_END
+
 NAME: icp_port udp_port
 TYPE: ushort
 DEFAULT: 3130
@@ -236,7 +334,7 @@
 DOC_START
         To specify other caches in a hierarchy, use the format:
 
- cache_peer hostname type http_port icp_port
+ cache_peer hostname type http_port icp_port [options]
 
         For example,
 
@@ -274,6 +372,13 @@
                      digest-url=url
                      allow-miss
                      max-conn
+ ssl
+ sslcert=/path/to/ssl/certificate
+ sslkey=/path/to/ssl/key
+ sslversion=1|2|3|4
+ sslcipher=...
+ ssloptions=...
+ front-end-https[=on|auto]
 
                      use 'proxy-only' to specify that objects fetched
                      from this cache should not be saved locally.
@@ -363,6 +468,64 @@
                      use 'max-conn' to limit the amount of connections Squid
                      may open to this peer.
 
+ use 'ssl' to indicate that connections to this peer should
+ bs SSL/TLS encrypted.
+
+ use 'sslcert=/path/to/ssl/certificate' to specify a client
+ SSL certificate to use when connecting to this peer.
+
+ use 'sslkey=/path/to/ssl/key' to specify the private SSL
+ key corresponding to sslcert above. If 'sslkey' is not
+ specified then 'sslcert' is assumed to reference a
+ combined file containing both the certificate and the key.
+
+ use sslversion=1|2|3|4 to specify the SSL version to use
+ when connecting to this peer
+ 1 = automatic (default)
+ 2 = SSL v2 only
+ 3 = SSL v3 only
+ 4 = TLS v1 only
+
+ use sslcipher=... to specify the list of valid SSL chipers
+ to use when connecting to this peer
+
+ use ssloptions=... to specify various SSL engine options:
+ NO_SSLv2 Disallow the use of SSLv2
+ NO_SSLv3 Disallow the use of SSLv3
+ NO_TLSv1 Disallow the use of TLSv1
+ See src/ssl_support.c or the OpenSSL documentation for
+ a more complete list.
+
+ use cafile=... to specify a file containing additional
+ CA certificates to use when verifying the peer certificate
+
+ use capath=... to specify a directory containing additional
+ CA certificates to use when verifying the peer certificate
+
+ use sslflags=... to specify various flags modifying the
+ SSL implementation:
+ DONT_VERIFY_PEER
+ Accept certificates even if they fail to
+ verify.
+ NO_DEFAULT_CA
+ Don't use the default CA list built in
+ to OpenSSL.
+ DONT_VERIFY_DOMAIN
+ Don't verify that the peer certificate
+ matches the server name
+
+ use sslname= to specify the peer name as advertised
+ in it's certificate. Used for verifying the correctness
+ of the received peer certificate. If not specified the
+ peer hostname will be used.
+
+ use front-end-https to enable the "Front-End-Https: On"
+ header needed when using Squid as a SSL frontend infront
+ of Microsoft OWA. See MS KB document Q307347 for details
+ on this header. If set to auto then the header will
+ only be added if the request is forwarded as a https://
+ URL.
+
         NOTE: non-ICP neighbors must be specified as 'parent'.
 DOC_END
 
@@ -1465,6 +1628,8 @@
           %PROTO Requested protocol
           %PORT Requested port
           %METHOD Request method
+ %USER_CERT_xx SSL User certificate attribute xx
+ %USER_CA_xx SSL User certificate CA attribute xx
           %{Header} HTTP request header
           %{Hdr:member} HTTP request header list member
           %{Hdr:;member}
@@ -1987,6 +2152,14 @@
         acl acl_name external class_name [arguments...]
           # external ACL lookup via a helper class defined by the
           # external_acl_type directive.
+
+ acl aclname user_cert attribute values...
+ # match against attributes in a user SSL certificate
+ # attribute is one of DN/C/O/CN/L/ST
+
+ acl aclname ca_cert attribute values...
+ # match against attributes a users issuing CA SSL certificate
+ # attribute is one of DN/C/O/CN/L/ST
 
 Examples:
 acl myexample dst_as 1241
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.1.2.9 squid/src/client_side.c:1.1.2.1.2.11
--- squid/src/client_side.c:1.1.2.9 Mon Nov 11 23:13:18 2002
+++ squid/src/client_side.c Mon Nov 11 23:13:43 2002
@@ -818,6 +818,9 @@
             packerClean(&p);
             memBufClean(&mb);
         }
+#if USE_SSL
+ http->al.cache.ssluser = sslGetUserEmail(fd_table[conn->fd].ssl);
+#endif
         accessLogLog(&http->al);
         clientUpdateCounters(http);
         clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
@@ -3320,20 +3323,25 @@
 {
     ConnStateData *conn = data;
     X509 *client_cert;
+ SSL *ssl = fd_table[fd].ssl;
     int ret;
 
- if ((ret = SSL_accept(fd_table[fd].ssl)) <= 0) {
- if (BIO_sock_should_retry(ret)) {
+ if ((ret = SSL_accept(ssl)) <= 0) {
+ int ssl_error = SSL_get_error(ssl, ret);
+ switch (ssl_error) {
+ case SSL_ERROR_WANT_READ:
             commSetSelect(fd, COMM_SELECT_READ, clientNegotiateSSL, conn, 0);
             return;
+ case SSL_ERROR_WANT_WRITE:
+ commSetSelect(fd, COMM_SELECT_WRITE, clientNegotiateSSL, conn, 0);
+ return;
+ default:
+ debug(81, 1) ("clientNegotiateSSL: Error negotiating SSL connection on FD %d: %s (%d/%d)\n",
+ fd, ERR_error_string(ERR_get_error(), NULL), ssl_error, ret);
+ comm_close(fd);
+ return;
         }
- ret = ERR_get_error();
- if (ret) {
- debug(83, 1) ("clientNegotiateSSL: Error negotiating SSL connection on FD %d: %s\n",
- fd, ERR_error_string(ret, NULL));
- }
- comm_close(fd);
- return;
+ /* NOTREACHED */
     }
     debug(83, 5) ("clientNegotiateSSL: FD %d negotiated cipher %s\n", fd,
         SSL_get_cipher(fd_table[fd].ssl));
@@ -3613,7 +3621,7 @@
             continue;
         CBDATA_INIT_TYPE(https_port_data);
         https_port = cbdataAlloc(https_port_data);
- https_port->sslContext = sslCreateContext(s->cert, s->key, s->version, s->cipher, s->options);
+ https_port->sslContext = s->sslContext;
         comm_listen(fd);
         commSetSelect(fd, COMM_SELECT_READ, httpsAccept, https_port, 0);
         commSetDefer(fd, httpAcceptDefer, NULL);
Index: squid/src/enums.h
diff -u squid/src/enums.h:1.1.2.2 squid/src/enums.h:1.1.2.1.2.3
--- squid/src/enums.h:1.1.2.2 Mon Sep 23 23:47:05 2002
+++ squid/src/enums.h Mon Nov 11 22:38:18 2002
@@ -136,6 +136,10 @@
     ACL_REP_MIME_TYPE,
     ACL_MAX_USER_IP,
     ACL_EXTERNAL,
+#if USE_SSL
+ ACL_USER_CERT,
+ ACL_CA_CERT,
+#endif
     ACL_ENUM_MAX
 } squid_acl;
 
@@ -246,6 +250,7 @@
 #if X_ACCELERATOR_VARY
     HDR_X_ACCELERATOR_VARY,
 #endif
+ HDR_FRONT_END_HTTPS,
     HDR_OTHER,
     HDR_ENUM_END
 } http_hdr_type;
@@ -616,6 +621,9 @@
     MEM_TLV,
     MEM_SWAP_LOG_DATA,
     MEM_CLIENT_REQ_BUF,
+#if USE_SSL
+ MEM_ACL_CERT_DATA,
+#endif
     MEM_MAX
 } mem_type;
 
Index: squid/src/external_acl.c
diff -u squid/src/external_acl.c:1.1.2.8 squid/src/external_acl.c:1.1.2.1.2.8
--- squid/src/external_acl.c:1.1.2.8 Mon Nov 11 18:41:03 2002
+++ squid/src/external_acl.c Mon Nov 11 22:33:31 2002
@@ -93,7 +93,8 @@
 
 struct _external_acl_format {
     enum {
- EXT_ACL_LOGIN = 1,
+ EXT_ACL_UNKNOWN,
+ EXT_ACL_LOGIN,
 #if USE_IDENT
         EXT_ACL_IDENT,
 #endif
@@ -105,7 +106,12 @@
         EXT_ACL_HEADER,
         EXT_ACL_HEADER_MEMBER,
         EXT_ACL_HEADER_ID,
- EXT_ACL_HEADER_ID_MEMBER
+ EXT_ACL_HEADER_ID_MEMBER,
+#if USE_SSL
+ EXT_ACL_USER_CERT,
+ EXT_ACL_CA_CERT,
+#endif
+ EXT_ACL_END
     } type;
     external_acl_format *next;
     char *header;
@@ -251,6 +257,15 @@
             format->type = EXT_ACL_PORT;
         else if (strcmp(token, "%METHOD") == 0)
             format->type = EXT_ACL_METHOD;
+#if USE_SSL
+ else if (strncmp(token, "%USER_CERT_", 11)) {
+ format->type = EXT_ACL_USER_CERT;
+ format->header = xstrdup(token + 11);
+ } else if (strncmp(token, "%CA_CERT_", 11)) {
+ format->type = EXT_ACL_USER_CERT;
+ format->header = xstrdup(token + 11);
+ }
+#endif
         else {
             self_destruct();
         }
@@ -313,6 +328,16 @@
                 DUMP_EXT_ACL_TYPE(PROTO);
                 DUMP_EXT_ACL_TYPE(PORT);
                 DUMP_EXT_ACL_TYPE(METHOD);
+ case EXT_ACL_USER_CERT:
+ storeAppendPrintf(sentry, " %%USER_CERT_%s", format->header);
+ break;
+ case EXT_ACL_CA_CERT:
+ storeAppendPrintf(sentry, " %%USER_CERT_%s", format->header);
+ break;
+ case EXT_ACL_UNKNOWN:
+ case EXT_ACL_END:
+ fatal("unknown external_acl format error");
+ break;
             }
         }
         for (word = node->cmdline; word; word = word->next)
@@ -535,6 +560,26 @@
         case EXT_ACL_HEADER_ID_MEMBER:
             sb = httpHeaderGetListMember(&request->header, format->header_id, format->member, format->separator);
             str = strBuf(sb);
+ break;
+#if USE_SSL
+ case EXT_ACL_USER_CERT:
+ if (cbdataValid(ch->conn)) {
+ SSL *ssl = fd_table[ch->conn->fd].ssl;
+ if (ssl)
+ str = sslGetUserAttribute(ssl, format->header);
+ }
+ break;
+ case EXT_ACL_CA_CERT:
+ if (cbdataValid(ch->conn)) {
+ SSL *ssl = fd_table[ch->conn->fd].ssl;
+ if (ssl)
+ str = sslGetCAAttribute(ssl, format->header);
+ }
+ break;
+#endif
+ case EXT_ACL_UNKNOWN:
+ case EXT_ACL_END:
+ fatal("unknown external_acl format error");
             break;
         }
         if (str)
Index: squid/src/forward.c
diff -u squid/src/forward.c:1.1.2.1 squid/src/forward.c:1.1.2.1.2.8
--- squid/src/forward.c:1.1.2.1 Mon Aug 12 19:17:20 2002
+++ squid/src/forward.c Thu Aug 22 14:32:59 2002
@@ -177,16 +177,106 @@
     }
 }
 
+#if USE_SSL
+static void
+fwdNegotiateSSL(int fd, void *data)
+{
+ FwdState *fwdState = data;
+ FwdServer *fs = fwdState->servers;
+ SSL *ssl = fd_table[fd].ssl;
+ int ret;
+ ErrorState *err;
+ request_t *request = fwdState->request;
+ if ((ret = SSL_connect(ssl)) <= 0) {
+ int ssl_error = SSL_get_error(ssl, ret);
+ switch (ssl_error) {
+ case SSL_ERROR_WANT_READ:
+ commSetSelect(fd, COMM_SELECT_READ, fwdNegotiateSSL, fwdState, 0);
+ return;
+ case SSL_ERROR_WANT_WRITE:
+ commSetSelect(fd, COMM_SELECT_WRITE, fwdNegotiateSSL, fwdState, 0);
+ return;
+ default:
+ debug(81, 1) ("fwdNegotiateSSL: Error negotiating SSL connection on FD %d: %s (%d/%d)\n", fd, ERR_error_string(ERR_get_error(), NULL), ssl_error, ret);
+ err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
+#ifdef EPROTO
+ err->xerrno = EPROTO;
+#else
+ err->xerrno = EACCES;
+#endif
+ if (fs->peer) {
+ err->host = xstrdup(fs->peer->host);
+ err->port = fs->peer->http_port;
+ } else {
+ err->host = xstrdup(request->host);
+ err->port = request->port;
+ }
+ err->request = requestLink(request);
+ fwdFail(fwdState, err);
+ if (fs->peer) {
+ peerConnectFailed(fs->peer);
+ fs->peer->stats.conn_open--;
+ }
+ comm_close(fd);
+ return;
+ }
+ }
+ fwdDispatch(fwdState);
+}
+
+static void
+fwdInitiateSSL(FwdState * fwdState)
+{
+ FwdServer *fs = fwdState->servers;
+ int fd = fwdState->server_fd;
+ SSL *ssl;
+ SSL_CTX *sslContext = NULL;
+ peer *peer = fs->peer;
+ if (peer) {
+ assert(peer->use_ssl);
+ sslContext = peer->sslContext;
+ } else {
+ sslContext = Config.ssl_client.sslContext;
+ }
+ assert(sslContext);
+ if ((ssl = SSL_new(sslContext)) == NULL) {
+ ErrorState *err;
+ debug(83, 1) ("fwdInitiateSSL: Error allocating handle: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
+ err->xerrno = errno;
+ err->request = requestLink(fwdState->request);
+ fwdFail(fwdState, err);
+ fwdStateFree(fwdState);
+ return;
+ }
+ SSL_set_fd(ssl, fd);
+ if (peer) {
+ if (peer->ssldomain)
+ SSL_set_ex_data(ssl, ssl_ex_index_server, peer->ssldomain);
+#if NOT_YET
+ else if (peer->name)
+ SSL_set_ex_data(ssl, ssl_ex_index_server, peer->name);
+#endif
+ else
+ SSL_set_ex_data(ssl, ssl_ex_index_server, peer->host);
+ } else {
+ SSL_set_ex_data(ssl, ssl_ex_index_server, fwdState->request->host);
+ }
+ fd_table[fd].ssl = ssl;
+ fd_table[fd].read_method = &ssl_read_method;
+ fd_table[fd].write_method = &ssl_write_method;
+ fwdNegotiateSSL(fd, fwdState);
+}
+#endif
+
 static void
 fwdConnectDone(int server_fd, int status, void *data)
 {
     FwdState *fwdState = data;
- static FwdState *current = NULL;
     FwdServer *fs = fwdState->servers;
     ErrorState *err;
     request_t *request = fwdState->request;
- assert(current != fwdState);
- current = fwdState;
     assert(fwdState->server_fd == server_fd);
     if (status == COMM_ERR_DNS) {
         /*
@@ -226,18 +316,16 @@
     } else {
         debug(17, 3) ("fwdConnectDone: FD %d: '%s'\n", server_fd, storeUrl(fwdState->entry));
         if (fs->peer)
- hierarchyNote(&fwdState->request->hier, fs->code, fs->peer->host);
- else if (Config.onoff.log_ip_on_direct)
- hierarchyNote(&fwdState->request->hier, fs->code, fd_table[server_fd].ipaddr);
- else
- hierarchyNote(&fwdState->request->hier, fs->code, request->host);
- fd_note(server_fd, storeUrl(fwdState->entry));
- fd_table[server_fd].uses++;
- if (fs->peer)
             peerConnectSucceded(fs->peer);
+#if USE_SSL
+ if ((fs->peer && fs->peer->use_ssl) ||
+ (!fs->peer && request->protocol == PROTO_HTTPS)) {
+ fwdInitiateSSL(fwdState);
+ return;
+ }
+#endif
         fwdDispatch(fwdState);
     }
- current = NULL;
 }
 
 static void
@@ -354,7 +442,7 @@
         fwdState->server_fd = fd;
         fwdState->n_tries++;
         comm_add_close_handler(fd, fwdServerClosed, fwdState);
- fwdConnectDone(fd, COMM_OK, fwdState);
+ fwdDispatch(fwdState);
         return;
     }
 #if URL_CHECKSUM_DEBUG
@@ -431,21 +519,31 @@
     request_t *request = fwdState->request;
     StoreEntry *entry = fwdState->entry;
     ErrorState *err;
+ FwdServer *fs = fwdState->servers;
+ int server_fd = fwdState->server_fd;
     debug(17, 3) ("fwdDispatch: FD %d: Fetching '%s %s'\n",
         fwdState->client_fd,
         RequestMethodStr[request->method],
         storeUrl(entry));
- /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
- assert(entry->ping_status != PING_WAITING);
- assert(entry->lock_count);
- EBIT_SET(entry->flags, ENTRY_DISPATCHED);
- netdbPingSite(request->host);
     /*
      * Assert that server_fd is set. This is to guarantee that fwdState
      * is attached to something and will be deallocated when server_fd
      * is closed.
      */
- assert(fwdState->server_fd > -1);
+ assert(server_fd > -1);
+ if (fs->peer)
+ hierarchyNote(&fwdState->request->hier, fs->code, fs->peer->host);
+ else if (Config.onoff.log_ip_on_direct)
+ hierarchyNote(&fwdState->request->hier, fs->code, fd_table[server_fd].ipaddr);
+ else
+ hierarchyNote(&fwdState->request->hier, fs->code, request->host);
+ fd_note(server_fd, storeUrl(fwdState->entry));
+ fd_table[server_fd].uses++;
+ /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
+ assert(entry->ping_status != PING_WAITING);
+ assert(entry->lock_count);
+ EBIT_SET(entry->flags, ENTRY_DISPATCHED);
+ netdbPingSite(request->host);
     if (fwdState->servers && (p = fwdState->servers->peer)) {
         p->stats.fetches++;
         fwdState->request->peer_login = p->login;
@@ -453,6 +551,11 @@
     } else {
         fwdState->request->peer_login = NULL;
         switch (request->protocol) {
+#if USE_SSL
+ case PROTO_HTTPS:
+ httpStart(fwdState);
+ break;
+#endif
         case PROTO_HTTP:
             httpStart(fwdState);
             break;
Index: squid/src/globals.h
diff -u squid/src/globals.h:1.1.2.1 squid/src/globals.h:1.1.2.1.2.3
--- squid/src/globals.h:1.1.2.1 Mon Aug 12 19:17:20 2002
+++ squid/src/globals.h Wed Aug 14 23:04:53 2002
@@ -164,4 +164,7 @@
 extern char *WIN32_OS_string; /* NULL */
 #endif
 
+extern int ssl_ex_index_server; /* -1 */
+extern int ssl_ctx_ex_index_dont_verify_domain; /* -1 */
+
 #endif /* SQUID_GLOBALS_H */
Index: squid/src/http.c
diff -u squid/src/http.c:1.1.2.2 squid/src/http.c:1.1.2.1.2.2
--- squid/src/http.c:1.1.2.2 Sun Sep 8 01:17:46 2002
+++ squid/src/http.c Mon Nov 11 22:38:18 2002
@@ -832,6 +832,10 @@
         case HDR_CACHE_CONTROL:
             /* append these after the loop if needed */
             break;
+ case HDR_FRONT_END_HTTPS:
+ if (!flags.front_end_https)
+ httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+ break;
         default:
             /* pass on all other header fields */
             httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
@@ -912,6 +916,12 @@
             httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
         }
     }
+ /* append Front-End-Https */
+ if (flags.front_end_https) {
+ if (flags.front_end_https == 1 || request->protocol == PROTO_HTTPS)
+ httpHeaderPutStr(hdr_out, HDR_FRONT_END_HTTPS, "On");
+ }
+
     /* Now mangle the headers. */
     httpHdrMangleList(hdr_out, request);
     stringClean(&strConnection);
@@ -985,10 +995,12 @@
         httpState->flags.keepalive = 1;
     else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
         httpState->flags.keepalive = 1;
- if (httpState->peer)
+ if (httpState->peer) {
         if (neighborType(httpState->peer, httpState->request) == PEER_SIBLING &&
             !httpState->peer->options.allow_miss)
             httpState->flags.only_if_cached = 1;
+ httpState->flags.front_end_https = httpState->peer->front_end_https;
+ }
     memBufDefInit(&mb);
     httpBuildRequestPrefix(req,
         httpState->orig_request,
@@ -1019,7 +1031,7 @@
         httpState->peer = fwd->servers->peer; /* might be NULL */
     if (httpState->peer) {
         proxy_req = requestCreate(orig_req->method,
- PROTO_NONE, storeUrl(httpState->entry));
+ orig_req->protocol, storeUrl(httpState->entry));
         xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN);
         proxy_req->port = httpState->peer->http_port;
         proxy_req->flags = orig_req->flags;
Index: squid/src/mem.c
diff -u squid/src/mem.c:1.1.2.1 squid/src/mem.c:1.1.2.1.2.1
--- squid/src/mem.c:1.1.2.1 Mon Aug 12 19:17:20 2002
+++ squid/src/mem.c Thu Aug 15 00:49:35 2002
@@ -199,6 +199,9 @@
     memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0);
     memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0);
     memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
+#if USE_SSL
+ memDataInit(MEM_ACL_CERT_DATA, "acl_cert_data", sizeof(acl_cert_data), 0);
+#endif
     memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
     memDataInit(MEM_AUTH_USER_T, "auth_user_t",
         sizeof(auth_user_t), 0);
Index: squid/src/ssl_support.c
diff -u squid/src/ssl_support.c:1.1.2.1 squid/src/ssl_support.c:1.1.2.1.2.13
--- squid/src/ssl_support.c:1.1.2.1 Mon Aug 12 19:17:21 2002
+++ squid/src/ssl_support.c Wed Nov 20 19:00:13 2002
@@ -55,12 +55,43 @@
 ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
 {
     char buffer[256];
+ SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
+ const char *server = SSL_get_ex_data(ssl, ssl_ex_index_server);
+ void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
+ X509 *peer_cert = ctx->cert;
 
- X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buffer,
+ X509_NAME_oneline(X509_get_subject_name(peer_cert), buffer,
         sizeof(buffer));
- if (ok)
- debug(83, 5) ("SSL Certificate OK: %s\n", buffer);
- else {
+
+ if (ok) {
+ debug(83, 5) ("SSL Certificate signature OK: %s\n", buffer);
+ if (server) {
+ int i;
+ int found = 0;
+ char cn[1024];
+ X509_NAME *name = X509_get_subject_name(peer_cert);
+ debug(83, 3) ("Verifying server domain %s to certificate dn %s\n",
+ server, buffer);
+ for (i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); i >= 0; i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) {
+ ASN1_STRING *data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
+ if (data->length > sizeof(cn) - 1)
+ continue;
+ memcpy(cn, data->data, data->length);
+ cn[data->length] = '\0';
+ debug(83, 4) ("Verifying server domain %s to certificate cn %s\n",
+ server, cn);
+ if (matchDomainName(server, cn[0] == '*' ? cn + 1 : cn) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ debug(83, 2) ("ERROR: Certificate %s does not match domainname %s\n", buffer, server);
+ ok = 0;
+ }
+ }
+ } else {
         switch (ctx->error) {
         case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
             debug(83, 5) ("SSL Certficate error: CA not known: %s\n", buffer);
@@ -78,11 +109,13 @@
             debug(83, 5) ("SSL Certificate has invalid \'not after\' field: %s\n", buffer);
             break;
         default:
- debug(83, 5) ("SSL unknown certificate error %d in %s\n",
+ debug(83, 1) ("SSL unknown certificate error %d in %s\n",
                 ctx->error, buffer);
             break;
         }
     }
+ if (!dont_verify_domain && server) {
+ }
     return ok;
 }
 
@@ -225,22 +258,88 @@
     return op;
 }
 
-SSL_CTX *
-sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options)
+#define SSL_FLAG_NO_DEFAULT_CA (1<<0)
+#define SSL_FLAG_DELAYED_AUTH (1<<1)
+#define SSL_FLAG_DONT_VERIFY_PEER (1<<2)
+#define SSL_FLAG_DONT_VERIFY_DOMAIN (1<<3)
+
+static long
+ssl_parse_flags(const char *flags)
+{
+ long fl = 0;
+ char *tmp;
+ char *flag;
+
+ if (!flags)
+ return 0;
+
+ tmp = xstrdup(flags);
+ flag = strtok(tmp, ":,");
+ while (flag) {
+ if (strcmp(flag, "NO_DEFAULT_CA") == 0)
+ fl |= SSL_FLAG_NO_DEFAULT_CA;
+ else if (strcmp(flag, "DELAYED_AUTH") == 0)
+ fl |= SSL_FLAG_DELAYED_AUTH;
+ else if (strcmp(flag, "DONT_VERIFY_PEER") == 0)
+ fl |= SSL_FLAG_DONT_VERIFY_PEER;
+ else if (strcmp(flag, "DONT_VERIFY_DOMAIN") == 0)
+ fl |= SSL_FLAG_DONT_VERIFY_DOMAIN;
+ else
+ fatalf("Unknown ssl flag '%s'", flag);
+ flag = strtok(NULL, ":,");
+ }
+ safe_free(tmp);
+ return fl;
+}
+
+
+static void
+ssl_initialize(void)
 {
- int ssl_error;
- SSL_METHOD *method;
- SSL_CTX *sslContext;
     static int ssl_initialized = 0;
     if (!ssl_initialized) {
         ssl_initialized = 1;
         SSL_load_error_strings();
         SSLeay_add_ssl_algorithms();
+#ifdef HAVE_OPENSSL_ENGINE_H
+ if ( Config.SSL.ssl_engine ) {
+ ENGINE *e;
+ if ( !(e = ENGINE_by_id(Config.SSL.ssl_engine)) ) {
+ fatalf("Unable to find SSL engine '%s'\n", Config.SSL.ssl_engine);
+ }
+ if ( !ENGINE_set_default(e,ENGINE_METHOD_ALL) ) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to initialise SSL engine: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ }
+ }
+#else
+ if ( Config.SSL.ssl_engine ) {
+ fatalf("Your OpenSSL has no SSL engine support\n");
+ }
+#endif
     }
+ ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", NULL, NULL, NULL);
+ ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", NULL, NULL, NULL);
+
+}
+
+SSL_CTX *
+sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath)
+{
+ int ssl_error;
+ SSL_METHOD *method;
+ SSL_CTX *sslContext;
+ long fl = ssl_parse_flags(flags);
+
+ ssl_initialize();
+
     if (!keyfile)
         keyfile = certfile;
     if (!certfile)
         certfile = keyfile;
+ if (!CAfile)
+ CAfile = clientCA;
 
     debug(83, 1) ("Initialising SSL.\n");
     switch (version) {
@@ -275,41 +374,168 @@
         debug(83, 5) ("Using chiper suite %s.\n", cipher);
         if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
             ssl_error = ERR_get_error();
- fatalf("Failed to set SSL cipher suite: %s\n",
- ERR_error_string(ssl_error, NULL));
+ fatalf("Failed to set SSL cipher suite '%s': %s\n",
+ cipher, ERR_error_string(ssl_error, NULL));
         }
     }
     debug(83, 1) ("Using certificate in %s\n", certfile);
- if (!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)) {
+ if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
         ssl_error = ERR_get_error();
- fatalf("Failed to acquire SSL certificate: %s\n",
- ERR_error_string(ssl_error, NULL));
+ debug(83, 1) ("Failed to acquire SSL certificate '%s': %s\n",
+ certfile, ERR_error_string(ssl_error, NULL));
+ goto error;
     }
     debug(83, 1) ("Using private key in %s\n", keyfile);
     if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) {
         ssl_error = ERR_get_error();
- fatalf("Failed to acquire SSL private key: %s\n",
- ERR_error_string(ssl_error, NULL));
+ debug(83, 1) ("Failed to acquire SSL private key '%s': %s\n",
+ keyfile, ERR_error_string(ssl_error, NULL));
+ goto error;
     }
     debug(83, 5) ("Comparing private and public SSL keys.\n");
- if (!SSL_CTX_check_private_key(sslContext))
- fatal("SSL private key does not match public key: %s\n");
+ if (!SSL_CTX_check_private_key(sslContext)) {
+ ssl_error = ERR_get_error();
+ debug(83, 0) ("SSL private key '%s' does not match public key '%s': %s\n",
+ certfile, keyfile, ERR_error_string(ssl_error, NULL));
+ goto error;
+ }
+ debug(83, 9) ("Setting RSA key generation callback.\n");
+ SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+
+ debug(83, 9) ("Setting CA certificate locations.\n");
+ if ((!SSL_CTX_load_verify_locations(sslContext, CAfile, CApath))) {
+ ssl_error = ERR_get_error();
+ debug(83, 1) ("Error error setting CA certificate locations: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ debug(83, 1) ("continuing anyway...\n");
+ }
+ if (!(fl & SSL_FLAG_NO_DEFAULT_CA) &&
+ !SSL_CTX_set_default_verify_paths(sslContext)) {
+ ssl_error = ERR_get_error();
+ debug(83, 1) ("Error error setting default CA certificate location: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ debug(83, 1) ("continuing anyway...\n");
+ }
+ if (clientCA) {
+ debug(83, 9) ("Set client certifying authority list.\n");
+ SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(clientCA));
+ if (fl & SSL_FLAG_DELAYED_AUTH) {
+ debug(83, 9) ("Not requesting client certificates until acl processing requires one\n");
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+ } else {
+ debug(83, 9) ("Requiring client certificates.\n");
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+ }
+ } else {
+ debug(83, 9) ("Not requiring any client certificates\n");
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+ }
+
+ if (fl & SSL_FLAG_DONT_VERIFY_DOMAIN)
+ SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
+ return sslContext;
+ error:
+ SSL_CTX_free(sslContext);
+ return NULL;
+}
+
+SSL_CTX *
+sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath)
+{
+ int ssl_error;
+ SSL_METHOD *method;
+ SSL_CTX *sslContext;
+ long fl = ssl_parse_flags(flags);
+
+ ssl_initialize();
+
+ if (!keyfile)
+ keyfile = certfile;
+ if (!certfile)
+ certfile = keyfile;
+
+ debug(83, 1) ("Initialising SSL.\n");
+ switch (version) {
+ case 2:
+ debug(83, 5) ("Using SSLv2.\n");
+ method = SSLv2_client_method();
+ break;
+ case 3:
+ debug(83, 5) ("Using SSLv3.\n");
+ method = SSLv3_client_method();
+ break;
+ case 4:
+ debug(83, 5) ("Using TLSv1.\n");
+ method = TLSv1_client_method();
+ break;
+ case 1:
+ default:
+ debug(83, 5) ("Using SSLv2/SSLv3.\n");
+ method = SSLv23_client_method();
+ break;
+ }
+
+ sslContext = SSL_CTX_new(method);
+ if (sslContext == NULL) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to allocate SSL context: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ }
+ SSL_CTX_set_options(sslContext, ssl_parse_options(options));
 
+ if (cipher) {
+ debug(83, 5) ("Using chiper suite %s.\n", cipher);
+ if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to set SSL cipher suite '%s': %s\n",
+ cipher, ERR_error_string(ssl_error, NULL));
+ }
+ }
+ if (certfile) {
+ debug(83, 1) ("Using certificate in %s\n", certfile);
+ if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to acquire SSL certificate '%s': %s\n",
+ certfile, ERR_error_string(ssl_error, NULL));
+ }
+ debug(83, 1) ("Using private key in %s\n", keyfile);
+ if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to acquire SSL private key '%s': %s\n",
+ keyfile, ERR_error_string(ssl_error, NULL));
+ }
+ debug(83, 5) ("Comparing private and public SSL keys.\n");
+ if (!SSL_CTX_check_private_key(sslContext)) {
+ ssl_error = ERR_get_error();
+ fatalf("SSL private key '%s' does not match public key '%s': %s\n",
+ certfile, keyfile, ERR_error_string(ssl_error, NULL));
+ }
+ }
     debug(83, 9) ("Setting RSA key generation callback.\n");
     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
 
- debug(83, 9) ("Setting certificate verification callback.\n");
- SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
+ if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
+ debug(83, 1) ("NOTICE: Peer certificates are not verified for validity!\n");
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+ } else {
+ debug(83, 9) ("Setting certificate verification callback.\n");
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+ }
 
- debug(83, 9) ("Setting default CA certificate location.\n");
- if (!SSL_CTX_set_default_verify_paths(sslContext)) {
+ debug(83, 9) ("Setting CA certificate locations.\n");
+ if ((!SSL_CTX_load_verify_locations(sslContext, CAfile, CApath))) {
+ ssl_error = ERR_get_error();
+ debug(83, 1) ("Error error setting CA certificate locations: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ debug(83, 1) ("continuing anyway...\n");
+ }
+ if (!(fl & SSL_FLAG_NO_DEFAULT_CA) &&
+ !SSL_CTX_set_default_verify_paths(sslContext)) {
         ssl_error = ERR_get_error();
         debug(83, 1) ("Error error setting default CA certificate location: %s\n",
             ERR_error_string(ssl_error, NULL));
         debug(83, 1) ("continuing anyway...\n");
     }
- debug(83, 9) ("Set client certifying authority list.\n");
- SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
     return sslContext;
 }
 
@@ -353,4 +579,92 @@
             SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
     }
     SSL_shutdown(ssl);
+}
+
+static const char *
+ssl_get_attribute(X509_NAME * name, const char *attribute_name)
+{
+ static char buffer[1024];
+ int nid;
+
+ buffer[0] = '\0';
+
+ if (strcmp(attribute_name, "DN") == 0) {
+ X509_NAME_oneline(name, buffer, sizeof(buffer));
+ goto done;
+ }
+ nid = OBJ_txt2nid((char *) attribute_name);
+ if (nid == 0) {
+ debug(83, 1) ("WARNING: Unknown SSL attribute name '%s'\n", attribute_name);
+ return NULL;
+ }
+ X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer));
+ done:
+ return *buffer ? buffer : NULL;
+}
+
+const char *
+sslGetUserAttribute(SSL * ssl, const char *attribute_name)
+{
+ X509 *cert;
+ X509_NAME *name;
+
+ if (!ssl)
+ return NULL;
+
+ cert = SSL_get_peer_certificate(ssl);
+ if (!cert)
+ return NULL;
+
+ name = X509_get_issuer_name(cert);
+
+ return ssl_get_attribute(name, attribute_name);
+}
+
+const char *
+sslGetCAAttribute(SSL * ssl, const char *attribute_name)
+{
+ X509 *cert;
+ X509_NAME *name;
+
+ if (!ssl)
+ return NULL;
+
+ cert = SSL_get_peer_certificate(ssl);
+ if (!cert)
+ return NULL;
+
+ name = X509_get_subject_name(cert);
+
+ return ssl_get_attribute(name, attribute_name);
+}
+
+#if 0
+char *
+sslGetUserEmail(SSL * ssl)
+{
+ X509 *cert;
+ X509_NAME *name;
+
+ static char email[128];
+
+ if (!ssl)
+ return NULL;
+ cert = SSL_get_peer_certificate(ssl);
+ if (!cert)
+ return NULL;
+
+ name = X509_get_subject_name(cert);
+
+ if (X509_NAME_get_text_by_NID(name, NID_pkcs9_emailAddress, email, sizeof(email)) > 0)
+ return email;
+ else
+ return NULL;
+}
+#endif
+
+const char *
+sslGetUserEmail(SSL * ssl)
+{
+ return sslGetUserAttribute(ssl, "Email");
 }
Index: squid/src/ssl_support.h
diff -u squid/src/ssl_support.h:1.1.2.1 squid/src/ssl_support.h:1.1.2.1.2.5
--- squid/src/ssl_support.h:1.1.2.1 Mon Aug 12 19:17:21 2002
+++ squid/src/ssl_support.h Wed Nov 20 19:00:13 2002
@@ -42,10 +42,18 @@
 #if HAVE_OPENSSL_ERR_H
 #include <openssl/err.h>
 #endif
+#if HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
 
-SSL_CTX *sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options);
+SSL_CTX *sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath);
+SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath);
 int ssl_read_method(int, char *, int);
 int ssl_write_method(int, const char *, int);
 void ssl_shutdown_method(int);
+
+const char *sslGetUserEmail(SSL *ssl);
+const char *sslGetUserAttribute(SSL *ssl, const char *attribute);
+const char *sslGetCAAttribute(SSL *ssl, const char *attribute);
 
 #endif /* SQUID_SSL_SUPPORT_H */
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.1.2.5 squid/src/structs.h:1.1.2.1.2.12
--- squid/src/structs.h:1.1.2.5 Mon Nov 11 18:41:03 2002
+++ squid/src/structs.h Wed Nov 20 19:00:13 2002
@@ -48,6 +48,13 @@
     dlink_node *tail;
 };
 
+#if USE_SSL
+struct _acl_cert_data {
+ splayNode *values;
+ char *attribute;
+};
+#endif
+
 struct _acl_user_data {
     splayNode *names;
     struct {
@@ -339,8 +346,12 @@
     int version;
     char *cipher;
     char *options;
+ char *clientca;
+ char *cafile;
+ char *capath;
+ char *sslflags;
+ SSL_CTX *sslContext;
 };
-
 #endif
 
 #if DELAY_POOLS
@@ -680,6 +691,7 @@
 #if USE_SSL
     struct {
         int unclean_shutdown;
+ char *ssl_engine;
     } SSL;
 #endif
     wordlist *ext_methods;
@@ -691,6 +703,19 @@
     char *store_dir_select_algorithm;
     int sleep_after_fork; /* microseconds */
     external_acl *externalAclHelperList;
+#if USE_SSL
+ struct {
+ char *cert;
+ char *key;
+ int version;
+ char *options;
+ char *cipher;
+ char *cafile;
+ char *capath;
+ char *flags;
+ SSL_CTX *sslContext;
+ } ssl_client;
+#endif
 };
 
 struct _SquidConfig2 {
@@ -966,6 +991,7 @@
     unsigned int proxying:1;
     unsigned int keepalive:1;
     unsigned int only_if_cached:1;
+ unsigned int front_end_https:2;
 };
 
 struct _HttpStateData {
@@ -1037,6 +1063,9 @@
         int msec;
         const char *rfc931;
         const char *authuser;
+#if USE_SSL
+ const char *ssluser;
+#endif
     } cache;
     struct {
         char *request;
@@ -1304,6 +1333,20 @@
     char *login; /* Proxy authorization */
     time_t connect_timeout;
     int max_conn;
+#if USE_SSL
+ int use_ssl;
+ char *sslcert;
+ char *sslkey;
+ int sslversion;
+ char *ssloptions;
+ char *sslcipher;
+ char *sslcafile;
+ char *sslcapath;
+ char *sslflags;
+ char *ssldomain;
+ SSL_CTX *sslContext;
+#endif
+ int front_end_https;
 };
 
 struct _net_db_name {
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.1.2.1 squid/src/typedefs.h:1.1.2.1.2.1
--- squid/src/typedefs.h:1.1.2.1 Mon Aug 12 19:17:21 2002
+++ squid/src/typedefs.h Thu Aug 15 00:49:35 2002
@@ -68,6 +68,9 @@
 typedef struct _acl_proxy_auth_match_cache acl_proxy_auth_match_cache;
 typedef struct _authscheme_entry authscheme_entry_t;
 typedef struct _authScheme authScheme;
+#if USE_SSL
+typedef struct _acl_cert_data acl_cert_data;
+#endif
 typedef struct _acl_user_data acl_user_data;
 typedef struct _acl_user_ip_data acl_user_ip_data;
 typedef struct _acl_arp_data acl_arp_data;
Received on Thu Nov 21 2002 - 10:30:00 MST

This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:18:47 MST