]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
SSL update from the "ssl" branch at SourceForge
authorhno <>
Sat, 20 Oct 2001 04:34:48 +0000 (04:34 +0000)
committerhno <>
Sat, 20 Oct 2001 04:34:48 +0000 (04:34 +0000)
* Several SSL tweaking options
  - SSL version per https_port, no longer a global setting
  - supported chipers, per https_port
  - supported protocols, per https_port
  - connection shutdown method

* Fix the bug reported by Noel Burton-Krahn where SSL connections
  could get hung with data pending in the SSL internal buffers. Mostly
  seen on large POST/PUT requests, but could in theory appear on any
  request larger than 4K.

src/cache_cf.cc
src/cf.data.pre
src/client_side.cc
src/comm.cc
src/comm_select.cc
src/ssl_support.cc
src/ssl_support.h
src/structs.h
src/win32.cc

index f31fa8358f133d193f9722b93f897459149843b6..ab24b84f955fd2570d5cf56dce0b430de9f60d7e 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.cc,v 1.393 2001/10/17 19:43:39 hno Exp $
+ * $Id: cache_cf.cc,v 1.394 2001/10/19 22:34:48 hno Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -2317,6 +2317,14 @@ parse_https_port_list(https_port_list ** head)
        } else if (strncmp(token, "key=", 4) == 0) {
            safe_free(s->key);
            s->key = xstrdup(token + 4);
+       } else if (strncmp(token, "version=", 8) == 0) {
+           s->version = atoi(token + 8);
+       } else if (strncmp(token, "options=", 8) == 0) {
+           safe_free(s->options);
+           s->options = xstrdup(token + 8);
+       } else if (strncmp(token, "cipher=", 7) == 0) {
+           safe_free(s->cipher);
+           s->cipher = xstrdup(token + 7);
        } else {
            self_destruct();
        }
@@ -2330,12 +2338,19 @@ static void
 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\"\n",
+       storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"",
            n,
            inet_ntoa(s->s.sin_addr),
            ntohs(s->s.sin_port),
            s->cert,
            s->key);
+       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);
+       storeAppendPrintf(e, "\n");
        s = s->next;
     }
 }
index 0246f79eab1ff71f8b1ee9f3b98e1c943e3a81bd..e8add8169dd7d5ef2388f66803b67bef92e0d0e5 100644 (file)
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.232 2001/10/10 15:17:40 adrian Exp $
+# $Id: cf.data.pre,v 1.233 2001/10/19 22:34:48 hno Exp $
 #
 #
 # SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -90,7 +90,7 @@ TYPE: https_port_list
 DEFAULT: none
 LOC: Config.Sockaddr.https
 DOC_START
-        Usage:  [ip:]port cert=certificate.pem [key=key.pem]
+        Usage:  [ip:]port cert=certificate.pem [key=key.pem] [...]
 
         The socket address where Squid will listen for HTTPS client
         requests.
@@ -102,24 +102,36 @@ DOC_START
        If key is not specified then the given certificate is assumed to be a
        combined certificate and key file.
 
+       Other options:
+
+         version=      The version of SSL/TLS supported
+                 1     automatic (default)
+                 2     SSLv2 only
+                 3     SSLv3 only
+                 4     TLSv1 only
+
+         cipher=       Colon separated list of supported ciphers
+
+         options=      Varions SSL engine options. The most important being:
+                 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 OpenSSL documentation for
+                       a more complete list.
+
        You may specify multiple socket addresses on multiple lines,
        each with their own SSL certificate.
 DOC_END
 
-NAME: ssl_version
-IFDEF: USE_SSL
-TYPE: int
-DEFAULT: 1
-LOC: Config.SSL.version
+NAME: ssl_unclean_shutdown
+TYPE: onoff
+DEFAULT: off
+LOC: Config.SSL.unclean_shutdown
 DOC_START
-        Determines the version of SSL/TLS used.
-        1:      SSLv2/SSLv3
-        2:      SSLv2 only
-        3:      SSLv3 only
-        4:      TLSv1
+       Some browsers (especially MSIE) bugs out on SSL shutdown
+       messages.
 DOC_END
 
-
 NAME: icp_port udp_port
 TYPE: ushort
 DEFAULT: 3130
index 13a38608fb225e851032698e2f282c99ecc75c85..814c7353329e76e293bf3fc9c31f1869a027c83c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.cc,v 1.548 2001/10/17 20:25:01 hno Exp $
+ * $Id: client_side.cc,v 1.549 2001/10/19 22:34:48 hno Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -3491,7 +3491,7 @@ clientHttpsConnectionsOpen(void)
            continue;
        CBDATA_INIT_TYPE(https_port_data);
        https_port = cbdataAlloc(https_port_data);
-       https_port->sslContext = sslLoadCert(s->cert, s->key);
+       https_port->sslContext = sslCreateContext(s->cert, s->key, s->version, s->cipher, s->options);
        comm_listen(fd);
        commSetSelect(fd, COMM_SELECT_READ, httpsAccept, https_port, 0);
        commSetDefer(fd, httpAcceptDefer, NULL);
index 3960c40c39a642c6b891d8fd9f39e037f0a18e0f..7cc1d42102da6fe0d9f3c65bf6778670e15b25da 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm.cc,v 1.322 2001/10/17 20:25:01 hno Exp $
+ * $Id: comm.cc,v 1.323 2001/10/19 22:34:49 hno Exp $
  *
  * DEBUG: section 5     Socket Functions
  * AUTHOR: Harvest Derived
@@ -602,7 +602,7 @@ comm_lingering_close(int fd)
 {
 #if USE_SSL
     if (fd_table[fd].ssl)
-       SSL_shutdown(fd_table[fd].ssl);
+       ssl_shutdown_method(fd);
 #endif
     if (shutdown(fd, 1) < 0) {
        comm_close(fd);
@@ -633,7 +633,7 @@ comm_close(int fd)
     F->flags.closing = 1;
 #if USE_SSL
     if (F->ssl)
-       SSL_shutdown(F->ssl);
+       ssl_shutdown_method(fd);
 #endif
     CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
     commCallCloseHandlers(fd);
index 50cd18e41550858f9254dad07276312597a758bc..6bd1f9c8f98897795fc955e7a49ed35b059ad669 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm_select.cc,v 1.50 2001/05/04 13:37:42 hno Exp $
+ * $Id: comm_select.cc,v 1.51 2001/10/19 22:34:49 hno Exp $
  *
  * DEBUG: section 5     Socket Functions
  *
@@ -317,6 +317,7 @@ comm_poll(int msec)
     int i;
     int maxfd;
     unsigned long nfds;
+    unsigned long npending;
     int num;
     int callicp = 0, callhttp = 0;
     int calldns = 0;
@@ -341,6 +342,7 @@ comm_poll(int msec)
            comm_poll_http_incoming();
        callicp = calldns = callhttp = 0;
        nfds = 0;
+       npending = 0;
        maxfd = Biggest_FD + 1;
        for (i = 0; i < maxfd; i++) {
            int events;
@@ -370,19 +372,23 @@ comm_poll(int msec)
                pfds[nfds].events = events;
                pfds[nfds].revents = 0;
                nfds++;
+               if ((events & POLLRDNORM) && fd_table[i].flags.read_pending)
+                   npending++;
            }
        }
        if (nfds == 0) {
            assert(shutting_down);
            return COMM_SHUTDOWN;
        }
+       if (npending)
+           msec = 0;
        if (msec > MAX_POLL_TIME)
            msec = MAX_POLL_TIME;
        for (;;) {
            statCounter.syscalls.polls++;
            num = poll(pfds, nfds, msec);
            statCounter.select_loops++;
-           if (num >= 0)
+           if (num >= 0 || npending >= 0)
                break;
            if (ignoreErrno(errno))
                continue;
@@ -391,22 +397,27 @@ comm_poll(int msec)
            return COMM_ERROR;
            /* NOTREACHED */
        }
-       debug(5, num ? 5 : 8) ("comm_poll: %d FDs ready\n", num);
+       debug(5, num ? 5 : 8) ("comm_poll: %d+%d FDs ready\n", num, npending);
        statHistCount(&statCounter.select_fds_hist, num);
        /* Check timeout handlers ONCE each second. */
        if (squid_curtime > last_timeout) {
            last_timeout = squid_curtime;
            checkTimeouts();
        }
-       if (num == 0)
+       if (num == 0 && npending == 0)
            continue;
        /* scan each socket but the accept socket. Poll this 
         * more frequently to minimize losses due to the 5 connect 
         * limit in SunOS */
        for (i = 0; i < nfds; i++) {
            fde *F;
-           int revents;
-           if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
+           int revents = pfds[i].revents;
+           fd = pfds[i].fd;
+           if (fd == -1)
+               continue;
+           if (fd_table[fd].flags.read_pending)
+               revents |= POLLIN;
+           if (revents == 0)
                continue;
            if (fdIsIcp(fd)) {
                callicp = 1;
@@ -632,6 +643,7 @@ int
 comm_select(int msec)
 {
     fd_set readfds;
+    fd_set pendingfds;
     fd_set writefds;
 #if DELAY_POOLS
     fd_set slowfds;
@@ -640,6 +652,7 @@ comm_select(int msec)
     int fd;
     int maxfd;
     int num;
+    int pending;
     int callicp = 0, callhttp = 0;
     int calldns = 0;
     int maxindex;
@@ -649,6 +662,7 @@ comm_select(int msec)
     int i;
 #endif
     fd_mask *fdsp;
+    fd_mask *pfdsp;
     fd_mask tmask;
     static time_t last_timeout = 0;
     struct timeval poll_time;
@@ -675,7 +689,8 @@ comm_select(int msec)
            howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
        xmemcpy(&writefds, &global_writefds,
            howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
-       /* remove stalled FDs */
+       /* remove stalled FDs, and deal with pending descriptors */
+       pending = 0;
        maxindex = howmany(maxfd, FD_MASK_BITS);
        fdsp = (fd_mask *) & readfds;
        for (j = 0; j < maxindex; j++) {
@@ -700,6 +715,10 @@ comm_select(int msec)
                default:
                    fatalf("bad return value from commDeferRead(FD %d)\n", fd);
                }
+               if (FD_ISSET(fd, &readfds) && fd_table[fd].flags.read_pending) {
+                   FD_SET(fd, &pendingfds);
+                   pending++;
+               }
            }
        }
 #if DEBUG_FDBITS
@@ -727,13 +746,15 @@ comm_select(int msec)
        if (msec < 0)
            msec = MAX_POLL_TIME;
 #endif
+       if (pending)
+           msec = 0;
        for (;;) {
            poll_time.tv_sec = msec / 1000;
            poll_time.tv_usec = (msec % 1000) * 1000;
            statCounter.syscalls.selects++;
            num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
            statCounter.select_loops++;
-           if (num >= 0)
+           if (num >= 0 || pending > 0)
                break;
            if (ignoreErrno(errno))
                break;
@@ -743,10 +764,10 @@ comm_select(int msec)
            return COMM_ERROR;
            /* NOTREACHED */
        }
-       if (num < 0)
+       if (num < 0 && !pending)
            continue;
-       debug(5, num ? 5 : 8) ("comm_select: %d FDs ready at %d\n",
-           num, (int) squid_curtime);
+       debug(5, num ? 5 : 8) ("comm_select: %d+%d FDs ready at %d\n",
+           num, pending, (int) squid_curtime);
        statHistCount(&statCounter.select_fds_hist, num);
        /* Check lifetime and timeout handlers ONCE each second.
         * Replaces brain-dead check every time through the loop! */
@@ -754,13 +775,14 @@ comm_select(int msec)
            last_timeout = squid_curtime;
            checkTimeouts();
        }
-       if (num == 0)
+       if (num == 0 && pending == 0)
            continue;
        /* Scan return fd masks for ready descriptors */
        fdsp = (fd_mask *) & readfds;
+       pfdsp = (fd_mask *) & pendingfds;
        maxindex = howmany(maxfd, FD_MASK_BITS);
        for (j = 0; j < maxindex; j++) {
-           if ((tmask = fdsp[j]) == 0)
+           if ((tmask = (fdsp[j] | pfdsp[j])) == 0)
                continue;       /* no bits here */
            for (k = 0; k < FD_MASK_BITS; k++) {
                if (tmask == 0)
index a109083df5d6423272f9825b529288ad60942db1..f9c9ee66ed0dbae32e4e7106f44efc6c9c39d2de 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ssl_support.cc,v 1.3 2001/08/26 22:02:19 hno Exp $
+ * $Id: ssl_support.cc,v 1.4 2001/10/19 22:34:49 hno Exp $
  *
  * AUTHOR: Benno Rice
  * DEBUG: section 81     SSL accelerator support
@@ -86,8 +86,147 @@ ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
     return ok;
 }
 
+static struct ssl_option {
+    const char *name;
+    long value;
+} ssl_options[] = {
+
+    {
+       "MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG
+    },
+    {
+       "NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG
+    },
+    {
+       "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+    },
+    {
+       "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+    },
+    {
+       "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+    },
+    {
+       "MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING
+    },
+    {
+       "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+    },
+    {
+       "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
+    },
+    {
+       "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
+    },
+    {
+       "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
+    },
+    {
+       "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
+    },
+    {
+       "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
+    },
+    {
+       "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
+    },
+    {
+       "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
+    },
+    {
+       "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
+    },
+    {
+       "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
+    },
+    {
+       "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
+    },
+    {
+       "ALL", SSL_OP_ALL
+    },
+    {
+       "NO_SSLv2", SSL_OP_NO_SSLv2
+    },
+    {
+       "NO_SSLv3", SSL_OP_NO_SSLv3
+    },
+    {
+       "NO_TLSv1", SSL_OP_NO_TLSv1
+    },
+    {
+       "", 0
+    },
+    {
+       NULL, 0
+    }
+};
+
+static long 
+ssl_parse_options(const char *options)
+{
+    long op = SSL_OP_ALL;
+    char *tmp;
+    char *option;
+
+    if (!options)
+       goto no_options;
+
+    tmp = xstrdup(options);
+    option = strtok(tmp, ":,");
+    while (option) {
+       struct ssl_option *opt = NULL, *opttmp;
+       long value = 0;
+       enum {
+           MODE_ADD, MODE_REMOVE
+       } mode;
+       switch (*option) {
+       case '!':
+       case '-':
+           mode = MODE_REMOVE;
+           option++;
+           break;
+       case '+':
+           mode = MODE_ADD;
+           option++;
+           break;
+       default:
+           mode = MODE_ADD;
+           break;
+       }
+       for (opttmp = ssl_options; opttmp->name; opttmp++) {
+           if (strcmp(opttmp->name, option) == 0) {
+               opt = opttmp;
+               break;
+           }
+       }
+       if (opt)
+           value = opt->value;
+       else if (strncmp(option, "0x", 2) == 0) {
+           /* Special case.. hex specification */
+           value = strtol(option + 2, NULL, 16);
+       } else {
+           fatalf("Unknown SSL option '%s'", option);
+           value = 0;          /* Keep GCC happy */
+       }
+       switch (mode) {
+       case MODE_ADD:
+           op |= value;
+           break;
+       case MODE_REMOVE:
+           op &= ~value;
+           break;
+       }
+       option = strtok(NULL, ":,");
+    }
+
+    safe_free(tmp);
+  no_options:
+    return op;
+}
+
 SSL_CTX *
-sslLoadCert(const char *certfile, const char *keyfile)
+sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options)
 {
     int ssl_error;
     SSL_METHOD *method;
@@ -104,7 +243,7 @@ sslLoadCert(const char *certfile, const char *keyfile)
        certfile = keyfile;
 
     debug(81, 1) ("Initialising SSL.\n");
-    switch (Config.SSL.version) {
+    switch (version) {
     case 2:
        debug(81, 5) ("Using SSLv2.\n");
        method = SSLv2_server_method();
@@ -130,8 +269,16 @@ sslLoadCert(const char *certfile, const char *keyfile)
        fatalf("Failed to allocate SSL context: %s\n",
            ERR_error_string(ssl_error, NULL));
     }
-    SSL_CTX_set_options(sslContext, SSL_OP_ALL);
+    SSL_CTX_set_options(sslContext, ssl_parse_options(options));
 
+    if (cipher) {
+       debug(81, 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));
+       }
+    }
     debug(81, 1) ("Using certificate in %s\n", certfile);
     if (!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)) {
        ssl_error = ERR_get_error();
@@ -172,7 +319,17 @@ ssl_read_method(fd, buf, len)
      char *buf;
      int len;
 {
-    return (SSL_read(fd_table[fd].ssl, buf, len));
+    int i;
+
+    i = SSL_read(fd_table[fd].ssl, buf, len);
+
+    if (i > 0 && SSL_pending(fd_table[fd].ssl) > 0) {
+       debug(81, 2) ("SSL fd %d is pending\n", fd);
+       fd_table[fd].flags.read_pending = 1;
+    } else
+       fd_table[fd].flags.read_pending = 0;
+
+    return i;
 }
 
 int
@@ -183,3 +340,17 @@ ssl_write_method(fd, buf, len)
 {
     return (SSL_write(fd_table[fd].ssl, buf, len));
 }
+
+void
+ssl_shutdown_method(fd)
+{
+    SSL *ssl = fd_table[fd].ssl;
+    if (!fd_table[fd].ssl_shutdown) {
+       fd_table[fd].ssl_shutdown = 1;
+       if (Config.SSL.unclean_shutdown)
+           SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
+       else
+           SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+    }
+    SSL_shutdown(ssl);
+}
index cb9ac22ed152277ece81f5740b88bde9e303dbf3..0eecee36ab3230754f86060591fa6f99266d0385 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ssl_support.h,v 1.3 2001/10/08 16:18:33 hno Exp $
+ * $Id: ssl_support.h,v 1.4 2001/10/19 22:34:49 hno Exp $
  *
  * AUTHOR: Benno Rice
  *
@@ -43,8 +43,9 @@
 #include <openssl/err.h>
 #endif
 
-SSL_CTX *sslLoadCert(const char *certfile, const char *keyfile);
+SSL_CTX *sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options);
 int ssl_read_method(int, char *, int);
 int ssl_write_method(int, const char *, int);
+void ssl_shutdown_method(int);
 
 #endif /* SQUID_SSL_SUPPORT_H */
index 9f59b60f004f480b6d8f677bee2ca3e09ef0143b..6f2a1ee7b42bdb8b3e638a2d01b83d0f68eef377 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.405 2001/10/17 20:25:03 hno Exp $
+ * $Id: structs.h,v 1.406 2001/10/19 22:34:49 hno Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -330,6 +330,9 @@ struct _https_port_list {
     struct sockaddr_in s;
     char *cert;
     char *key;
+    int version;
+    char *cipher;
+    char *options;
 };
 
 #endif
@@ -668,9 +671,7 @@ struct _SquidConfig {
 #endif
 #if USE_SSL
     struct {
-       char *certificate;
-       char *key;
-       int version;
+       int unclean_shutdown;
     } SSL;
 #endif
     wordlist *ext_methods;
@@ -762,6 +763,7 @@ struct _fde {
        unsigned int called_connect:1;
        unsigned int nodelay:1;
        unsigned int close_on_exec:1;
+       unsigned int read_pending:1;
     } flags;
     int bytes_read;
     int bytes_written;
@@ -789,6 +791,7 @@ struct _fde {
     WRITE_HANDLER *write_method;
 #if USE_SSL
     SSL *ssl;
+    int ssl_shutdown:1;
 #endif
 };
 
index 1d3e8f277972ccafbf4064d8e7d51a98d98228b7..fa5a8f90003549786a0c4f5979b14aeaf22d3856 100644 (file)
@@ -1,5 +1,6 @@
+
 /*
- * $Id: win32.cc,v 1.2 2001/08/16 00:16:19 hno Exp $
+ * $Id: win32.cc,v 1.3 2001/10/19 22:34:49 hno Exp $
  *
  * * * * * * * * Legal stuff * * * * * * *
  *