--------------------- PatchSet 5519 Date: 2002/11/29 17:49:17 Author: hno Branch: ssl-2_5 Tag: (none) Log: Imported SSL update patch * Client certificate support * SSL encrypted peers support * Gatewaying of https:// URLs for non-SSL enabled browsers * Hardware SSL acceleration support * Some bugfixes & optimizations Members: configure.in:1.42.2.30->1.42.2.30.2.1 src/HttpHeader.c:1.10.6.4->1.10.6.4.2.1 src/access_log.c:1.15.6.2->1.15.6.2.2.1 src/acl.c:1.43.2.11->1.43.2.11.2.1 src/cache_cf.c:1.38.6.9->1.38.6.9.2.1 src/cf.data.pre:1.49.2.27->1.49.2.27.2.1 src/client_side.c:1.47.2.21->1.47.2.21.2.1 src/enums.h:1.29.2.7->1.29.2.7.2.1 src/external_acl.c:1.2.4.11->1.2.4.11.2.1 src/forward.c:1.13.6.1->1.13.6.1.8.1 src/globals.h:1.14.6.2->1.14.6.2.2.1 src/http.c:1.17.6.3->1.17.6.3.2.1 src/mem.c:1.13->1.13.24.1 src/ssl_support.c:1.6.6.1->1.6.6.1.2.1 src/ssl_support.h:1.5->1.5.44.1 src/structs.h:1.48.2.8->1.48.2.8.2.1 src/typedefs.h:1.25.6.1->1.25.6.1.2.1 Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.42.2.30 retrieving revision 1.42.2.30.2.1 diff -u -r1.42.2.30 -r1.42.2.30.2.1 --- squid/configure.in 22 Oct 2002 08:36:20 -0000 1.42.2.30 +++ squid/configure.in 29 Nov 2002 17:49:17 -0000 1.42.2.30.2.1 @@ -3,7 +3,7 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.42.2.30 2002/10/22 08:36:20 squidadm Exp $ +dnl $Id: configure.in,v 1.42.2.30.2.1 2002/11/29 17:49:17 hno Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AM_INIT_AUTOMAKE(squid, 2.5.STABLE1-CVS) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.42.2.30 $)dnl +AC_REVISION($Revision: 1.42.2.30.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpHeader.c,v retrieving revision 1.10.6.4 retrieving revision 1.10.6.4.2.1 diff -u -r1.10.6.4 -r1.10.6.4.2.1 --- squid/src/HttpHeader.c 25 Jun 2002 08:12:12 -0000 1.10.6.4 +++ squid/src/HttpHeader.c 29 Nov 2002 17:49:17 -0000 1.10.6.4.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpHeader.c,v 1.10.6.4 2002/06/25 08:12:12 squidadm Exp $ + * $Id: HttpHeader.c,v 1.10.6.4.2.1 2002/11/29 17:49:17 hno Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/access_log.c,v retrieving revision 1.15.6.2 retrieving revision 1.15.6.2.2.1 diff -u -r1.15.6.2 -r1.15.6.2.2.1 --- squid/src/access_log.c 16 Jun 2002 19:51:59 -0000 1.15.6.2 +++ squid/src/access_log.c 29 Nov 2002 17:49:17 -0000 1.15.6.2.2.1 @@ -1,6 +1,6 @@ /* - * $Id: access_log.c,v 1.15.6.2 2002/06/16 19:51:59 squidadm Exp $ + * $Id: access_log.c,v 1.15.6.2.2.1 2002/11/29 17:49:17 hno Exp $ * * DEBUG: section 46 Access Log * AUTHOR: Duane Wessels @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/acl.c,v retrieving revision 1.43.2.11 retrieving revision 1.43.2.11.2.1 diff -u -r1.43.2.11 -r1.43.2.11.2.1 --- squid/src/acl.c 10 Nov 2002 22:44:12 -0000 1.43.2.11 +++ squid/src/acl.c 29 Nov 2002 17:49:18 -0000 1.43.2.11.2.1 @@ -1,6 +1,6 @@ /* - * $Id: acl.c,v 1.43.2.11 2002/11/10 22:44:12 squidadm Exp $ + * $Id: acl.c,v 1.43.2.11.2.1 2002/11/29 17:49:18 hno Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v retrieving revision 1.38.6.9 retrieving revision 1.38.6.9.2.1 diff -u -r1.38.6.9 -r1.38.6.9.2.1 --- squid/src/cache_cf.c 15 Nov 2002 03:14:10 -0000 1.38.6.9 +++ squid/src/cache_cf.c 29 Nov 2002 17:49:18 -0000 1.38.6.9.2.1 @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.c,v 1.38.6.9 2002/11/15 03:14:10 squidadm Exp $ + * $Id: cache_cf.c,v 1.38.6.9.2.1 2002/11/29 17:49:18 hno Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v retrieving revision 1.49.2.27 retrieving revision 1.49.2.27.2.1 diff -u -r1.49.2.27 -r1.49.2.27.2.1 --- squid/src/cf.data.pre 10 Nov 2002 22:44:12 -0000 1.49.2.27 +++ squid/src/cf.data.pre 29 Nov 2002 17:49:18 -0000 1.49.2.27.2.1 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.49.2.27 2002/11/10 22:44:12 squidadm Exp $ +# $Id: cf.data.pre,v 1.49.2.27.2.1 2002/11/29 17:49:18 hno Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -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,85 @@ messages. DOC_END +NAME: ssl_engine +IFDEF: USE_SSL +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 +335,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 +373,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 +469,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 +1629,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} @@ -1988,6 +2154,14 @@ # 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 acl password proxy_auth REQUIRED Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.47.2.21 retrieving revision 1.47.2.21.2.1 diff -u -r1.47.2.21 -r1.47.2.21.2.1 --- squid/src/client_side.c 11 Nov 2002 22:16:28 -0000 1.47.2.21 +++ squid/src/client_side.c 29 Nov 2002 17:49:19 -0000 1.47.2.21.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.47.2.21 2002/11/11 22:16:28 squidadm Exp $ + * $Id: client_side.c,v 1.47.2.21.2.1 2002/11/29 17:49:19 hno Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/enums.h,v retrieving revision 1.29.2.7 retrieving revision 1.29.2.7.2.1 diff -u -r1.29.2.7 -r1.29.2.7.2.1 --- squid/src/enums.h 23 Sep 2002 21:46:19 -0000 1.29.2.7 +++ squid/src/enums.h 29 Nov 2002 17:49:19 -0000 1.29.2.7.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.29.2.7 2002/09/23 21:46:19 squidadm Exp $ + * $Id: enums.h,v 1.29.2.7.2.1 2002/11/29 17:49:19 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/external_acl.c,v retrieving revision 1.2.4.11 retrieving revision 1.2.4.11.2.1 diff -u -r1.2.4.11 -r1.2.4.11.2.1 --- squid/src/external_acl.c 10 Nov 2002 22:44:13 -0000 1.2.4.11 +++ squid/src/external_acl.c 29 Nov 2002 17:49:19 -0000 1.2.4.11.2.1 @@ -1,6 +1,6 @@ /* - * $Id: external_acl.c,v 1.2.4.11 2002/11/10 22:44:13 squidadm Exp $ + * $Id: external_acl.c,v 1.2.4.11.2.1 2002/11/29 17:49:19 hno Exp $ * * DEBUG: section 82 External ACL * AUTHOR: Henrik Nordstrom, MARA Systems AB @@ -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) @@ -536,6 +561,26 @@ 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) if (!*str) Index: squid/src/forward.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/forward.c,v retrieving revision 1.13.6.1 retrieving revision 1.13.6.1.8.1 diff -u -r1.13.6.1 -r1.13.6.1.8.1 --- squid/src/forward.c 1 Apr 2002 20:31:13 -0000 1.13.6.1 +++ squid/src/forward.c 29 Nov 2002 17:49:20 -0000 1.13.6.1.8.1 @@ -1,6 +1,6 @@ /* - * $Id: forward.c,v 1.13.6.1 2002/04/01 20:31:13 squidadm Exp $ + * $Id: forward.c,v 1.13.6.1.8.1 2002/11/29 17:49:20 hno Exp $ * * DEBUG: section 17 Request Forwarding * AUTHOR: Duane Wessels @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/globals.h,v retrieving revision 1.14.6.2 retrieving revision 1.14.6.2.2.1 diff -u -r1.14.6.2 -r1.14.6.2.2.1 --- squid/src/globals.h 15 Jul 2002 00:44:14 -0000 1.14.6.2 +++ squid/src/globals.h 29 Nov 2002 17:49:20 -0000 1.14.6.2.2.1 @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.14.6.2 2002/07/15 00:44:14 squidadm Exp $ + * $Id: globals.h,v 1.14.6.2.2.1 2002/11/29 17:49:20 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.17.6.3 retrieving revision 1.17.6.3.2.1 diff -u -r1.17.6.3 -r1.17.6.3.2.1 --- squid/src/http.c 7 Sep 2002 23:16:47 -0000 1.17.6.3 +++ squid/src/http.c 29 Nov 2002 17:49:20 -0000 1.17.6.3.2.1 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.17.6.3 2002/09/07 23:16:47 squidadm Exp $ + * $Id: http.c,v 1.17.6.3.2.1 2002/11/29 17:49:20 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/mem.c,v retrieving revision 1.13 retrieving revision 1.13.24.1 diff -u -r1.13 -r1.13.24.1 --- squid/src/mem.c 7 Sep 2001 23:55:49 -0000 1.13 +++ squid/src/mem.c 29 Nov 2002 17:49:20 -0000 1.13.24.1 @@ -1,6 +1,6 @@ /* - * $Id: mem.c,v 1.13 2001/09/07 23:55:49 squidadm Exp $ + * $Id: mem.c,v 1.13.24.1 2002/11/29 17:49:20 hno Exp $ * * DEBUG: section 13 High Level Memory Pool Management * AUTHOR: Harvest Derived @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ssl_support.c,v retrieving revision 1.6.6.1 retrieving revision 1.6.6.1.2.1 diff -u -r1.6.6.1 -r1.6.6.1.2.1 --- squid/src/ssl_support.c 21 Jul 2002 01:07:44 -0000 1.6.6.1 +++ squid/src/ssl_support.c 29 Nov 2002 17:49:20 -0000 1.6.6.1.2.1 @@ -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)) { + int 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; } @@ -354,3 +580,91 @@ } 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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ssl_support.h,v retrieving revision 1.5 retrieving revision 1.5.44.1 diff -u -r1.5 -r1.5.44.1 --- squid/src/ssl_support.h 19 Oct 2001 22:48:48 -0000 1.5 +++ squid/src/ssl_support.h 29 Nov 2002 17:49:20 -0000 1.5.44.1 @@ -42,10 +42,18 @@ #if HAVE_OPENSSL_ERR_H #include #endif +#if HAVE_OPENSSL_ENGINE_H +#include +#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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.48.2.8 retrieving revision 1.48.2.8.2.1 diff -u -r1.48.2.8 -r1.48.2.8.2.1 --- squid/src/structs.h 10 Nov 2002 22:44:13 -0000 1.48.2.8 +++ squid/src/structs.h 29 Nov 2002 17:49:20 -0000 1.48.2.8.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.48.2.8 2002/11/10 22:44:13 squidadm Exp $ + * $Id: structs.h,v 1.48.2.8.2.1 2002/11/29 17:49:20 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -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 =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.25.6.1 retrieving revision 1.25.6.1.2.1 diff -u -r1.25.6.1 -r1.25.6.1.2.1 --- squid/src/typedefs.h 23 Jun 2002 13:56:26 -0000 1.25.6.1 +++ squid/src/typedefs.h 29 Nov 2002 17:49:21 -0000 1.25.6.1.2.1 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.25.6.1 2002/06/23 13:56:26 squidadm Exp $ + * $Id: typedefs.h,v 1.25.6.1.2.1 2002/11/29 17:49:21 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -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;