[squid-dev] [PATCH] TLS NPN updates

Amos Jeffries squid3 at treenet.co.nz
Wed Dec 16 05:20:19 UTC 2015


Would help to actually attach the patch I suppose :-P

On 16/12/2015 6:19 p.m., Amos Jeffries wrote:
> This patch is shuffling the TLS NPN gadgetry into libsecurity.
> 
> It would be a non-audit commit except that ...
> 
> * there is a new config option added (tls-no-npn) to fully disable NPN
> on selected peers or ports.
> 
> * ICAPS connections are setting that option by default to prevent NPN
> wrongly advertising them as HTTPS connections.
> 
> 
> If there are no objections to those two small changes I would like to
> fast-track this patch and apply in ~48hrs.
> 

Amos

-------------- next part --------------
=== modified file 'doc/release-notes/release-4.sgml'
--- doc/release-notes/release-4.sgml	2015-11-28 14:18:32 +0000
+++ doc/release-notes/release-4.sgml	2015-12-15 23:29:25 +0000
@@ -154,70 +154,73 @@
 	<p>New tag to define TLS security context options for outgoing
 	   connections. For example to HTTPS servers.
 
 	<tag>url_rewrite_timeout</tag>
 	<p>Squid times active requests to redirector. This option sets
 	   the timeout value and the Squid reaction to a timed out
 	   request.
 
 </descrip>
 
 <sect1>Changes to existing tags<label id="modifiedtags">
 <p>
 <descrip>
 	<tag>auth_param</tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
 	   of queued requests.
 
 	<tag>cache_peer</tag>
 	<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
 	<p>New option <em>tls-no-default-ca</em> replaces <em>sslflags=NO_DEFAULT_CA</em>
+	<p>New option <em>tls-no-npn</em> to disable sending TLS NPN extension.
 	<p>All <em>ssloptions=</em> values for SSLv2 configuration or disabling
 	   have been removed.
 	<p>Removed <em>sslversion=</em> option. Use <em>tls-options=</em> instead.
 	<p>Manual squid.conf update may be required on upgrade.
 	<p>Replaced <em>sslcafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
 
 	<tag>external_acl_type</tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
 	   of queued requests.
 	<p>Format field updated to accept any logformat %macro code.
 
 	<tag>http_port</tag>
 	<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
 	<p>New option <em>tls-no-default-ca</em> replaces <em>sslflags=NO_DEFAULT_CA</em>
+	<p>New option <em>tls-no-npn</em> to disable sending TLS NPN extension.
 	<p>All <em>option=</em> values for SSLv2 configuration or disabling
 	   have been removed.
 	<p>Removed <em>version=</em> option. Use <em>tls-options=</em> instead.
 	<p>New <em>options=SINGLE_ECDH_USE</em> parameter to enable ephemeral
 	   ECDH key exchange.
 	<p>Deprecated <em>dhparams=</em> option. Use <em>tls-dh=</em> instead.
 	   The new option allows to optionally specify an elliptic curve for
 	   ephemeral ECDH by adding <em>curve-name:</em> in front of the
 	   parameter file name.
 	<p>Manual squid.conf update may be required on upgrade.
 	<p>Replaced <em>cafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
 	<p>New option <em>tls-no-default-ca</em> replaces <em>sslflags=NO_DEFAULT_CA</em>
 
 	<tag>https_port</tag>
 	<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
 	<p>New option <em>tls-no-default-ca</em> replaces <em>sslflags=NO_DEFAULT_CA</em>
+	<p>New option <em>tls-no-npn</em> to disable sending TLS NPN extension.
 	<p>All <em>options=</em> values for SSLv2
 	   configuration or disabling have been removed.
 	<p>Removed <em>version=</em> option. Use <em>tls-options=</em> instead.
 	<p>New <em>options=SINGLE_ECDH_USE</em> parameter to enable ephemeral
 	   ECDH key exchange.
 	<p>Deprecated <em>dhparams=</em> option. Use <em>tls-dh=</em> instead.
 	   The new option allows to optionally specify an elliptic curve for
 	   ephemeral ECDH by adding <em>curve-name:</em> in front of the
 	   parameter file name.
 	<p>Manual squid.conf update may be required on upgrade.
 	<p>Replaced <em>cafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
 
 	<tag>icap_service</tag>
 	<p>New scheme <em>icaps://</em> to enable TLS/SSL connections to Secure ICAP
 	   servers on port 11344.
 	<p>New <em>tls-cert=</em> option to set TLS client certificate to use.
 	<p>New <em>tls-key=</em> option to set TLS private key matching the client
 	   certificate used.
 	<p>New <em>tls-min-version=1.N</em> option to set minimum TLS version allowed
 	   on server connections.

=== modified file 'src/adaptation/ServiceConfig.cc'
--- src/adaptation/ServiceConfig.cc	2015-08-11 04:41:55 +0000
+++ src/adaptation/ServiceConfig.cc	2015-12-16 03:21:24 +0000
@@ -132,40 +132,45 @@
             debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: adaptation option '" << name << "' requires --with-openssl. ICAP service option ignored.");
 #else
             // name prefix is "ssl" or "tls-"
             std::string tmp = name + (name[0] == 's' ? 3 : 4);
             tmp += "=";
             tmp += value;
             secure.parse(tmp.c_str());
             grokked = true;
 #endif
         } else
             grokked = grokExtension(name, value);
 
         if (!grokked)
             return false;
     }
 
     // set default on-overload value if needed
     if (!onOverloadSet)
         onOverload = bypass ? srvBypass : srvWait;
 
+    // disable the TLS NPN extension if encrypted.
+    // Squid advertises "http/1.1", which is wrong for ICAPS.
+    if (secure.encryptTransport)
+        secure.parse("no-npn");
+
     // is the service URI set?
     if (!grokkedUri) {
         debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
                "No \"uri\" option in adaptation service definition");
         return false;
     }
 
     debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
            "adaptation_service " << key << ' ' <<
            methodStr() << "_" << vectPointStr() << ' ' <<
            bypass << routing << ' ' <<
            uri);
 
     return true;
 }
 
 bool
 Adaptation::ServiceConfig::grokUri(const char *value)
 {
     // TODO: find core code that parses URLs and extracts various parts

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2015-12-02 19:45:15 +0000
+++ src/cf.data.pre	2015-12-15 23:27:31 +0000
@@ -1958,40 +1958,42 @@
 				 this option is not set.
 
 	   sslflags=	Various flags modifying the use of SSL:
 			    DELAYED_AUTH
 				Don't request client certificates
 				immediately, but wait until acl processing
 				requires a certificate (not yet implemented).
 			    NO_SESSION_REUSE
 				Don't allow for session reuse. Each connection
 				will result in a new SSL session.
 			    VERIFY_CRL
 				Verify CRL lists when accepting client
 				certificates.
 			    VERIFY_CRL_ALL
 				Verify CRL lists for all certificates in the
 				client certificate chain.
 
 	   tls-no-default-ca
 			Do not use the system default Trusted CA.
 
+	   tls-no-npn	Do not use the TLS NPN extension to advertise HTTP/1.1.
+
 	   sslcontext=	SSL session ID context identifier.
 
 	Other Options:
 
 	   connection-auth[=on|off]
 	                use connection-auth=off to tell Squid to prevent 
 	                forwarding Microsoft connection oriented authentication
 			(NTLM, Negotiate and Kerberos)
 
 	   disable-pmtu-discovery=
 			Control Path-MTU discovery usage:
 			    off		lets OS decide on what to do (default).
 			    transparent	disable PMTU discovery when transparent
 					support is enabled.
 			    always	disable always PMTU discovery.
 
 			In many setups of transparently intercepting proxies
 			Path-MTU discovery can not work on traffic towards the
 			clients. This is the case when the intercepting device
 			does not fully track connections and fails to forward
@@ -3266,40 +3268,42 @@
 
 			DONT_VERIFY_DOMAIN
 				Don't verify the peer certificate
 				matches the server name
 	
 	ssldomain= 	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.
 	
 	front-end-https
 			Enable the "Front-End-Https: On" header needed when
 			using Squid as a SSL frontend in front of Microsoft OWA.
 			See MS KB document Q307347 for details on this header.
 			If set to auto the header will only be added if the
 			request is forwarded as a https:// URL.
 
 	tls-no-default-ca
 			Do not use the system default Trusted CA.	
 	
+	tls-no-npn	Do not use the TLS NPN extension to advertise HTTP/1.1.
+
 	==== GENERAL OPTIONS ====
 	
 	connect-timeout=N
 			A peer-specific connect timeout.
 			Also see the peer_connect_timeout directive.
 	
 	connect-fail-limit=N
 			How many times connecting to a peer must fail before
 			it is marked as down. Standby connection failures
 			count towards this limit. Default is 10.
 	
 	allow-miss	Disable Squid's use of only-if-cached when forwarding
 			requests to siblings. This is primarily useful when
 			icp_hit_stale is used by the sibling. Excessive use
 			of this option may result in forwarding loops. One way
 			to prevent peering loops when using this option, is to
 			deny cache peer usage on requests from a peer:
 			acl fromPeer ...
 			cache_peer_access peerName deny fromPeer
 	

=== modified file 'src/security/PeerOptions.cc'
--- src/security/PeerOptions.cc	2015-12-08 01:48:40 +0000
+++ src/security/PeerOptions.cc	2015-12-16 05:02:33 +0000
@@ -76,40 +76,42 @@
     } else if (strncmp(token, "cipher=", 7) == 0) {
         sslCipher = SBuf(token + 7);
     } else if (strncmp(token, "cafile=", 7) == 0) {
         caFiles.emplace_back(SBuf(token + 7));
     } else if (strncmp(token, "capath=", 7) == 0) {
         caDir = SBuf(token + 7);
 #if !USE_OPENSSL
         debugs(3, DBG_PARSE_NOTE(1), "WARNING: capath= option requires --with-openssl.");
 #endif
     } else if (strncmp(token, "crlfile=", 8) == 0) {
         crlFile = SBuf(token + 8);
         loadCrlFile();
     } else if (strncmp(token, "flags=", 6) == 0) {
         if (parsedFlags != 0) {
             debugs(3, DBG_PARSE_NOTE(1), "WARNING: Overwriting flags=" << sslFlags << " with " << SBuf(token + 6));
         }
         sslFlags = SBuf(token + 6);
         parsedFlags = parseFlags();
     } else if (strncmp(token, "domain=", 7) == 0) {
         sslDomain = SBuf(token + 7);
+    } else if (strncmp(token, "no-npn", 6) == 0) {
+        flags.noTlsNpn = true;
     } else {
         debugs(3, DBG_CRITICAL, "ERROR: Unknown TLS option '" << token << "'");
         return;
     }
 
     encryptTransport = true;
 }
 
 void
 Security::PeerOptions::dumpCfg(Packable *p, const char *pfx) const
 {
     if (!encryptTransport) {
         p->appendf(" %sdisable", pfx);
         return; // no other settings are relevant
     }
 
     for (auto &i : certs) {
         if (!i.certFile.isEmpty())
             p->appendf(" %scert=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i.certFile));
 
@@ -118,40 +120,43 @@
     }
 
     if (!sslOptions.isEmpty())
         p->appendf(" %soptions=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslOptions));
 
     if (!sslCipher.isEmpty())
         p->appendf(" %scipher=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslCipher));
 
     for (auto i : caFiles) {
         p->appendf(" %scafile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i));
     }
 
     if (!caDir.isEmpty())
         p->appendf(" %scapath=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(caDir));
 
     if (!crlFile.isEmpty())
         p->appendf(" %scrlfile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(crlFile));
 
     if (!sslFlags.isEmpty())
         p->appendf(" %sflags=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslFlags));
+
+    if (flags.noTlsNpn)
+        p->appendf(" %sno-npn", pfx);
 }
 
 void
 Security::PeerOptions::updateTlsVersionLimits()
 {
     if (!tlsMinVersion.isEmpty()) {
         ::Parser::Tokenizer tok(tlsMinVersion);
         int64_t v = 0;
         if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 3) {
             // only account for TLS here - SSL versions are handled by options= parameter
             // avoid affecting options= parameter in cachemgr config report
 #if SSL_OP_NO_TLSv1
             if (v > 0)
                 parsedOptions |= SSL_OP_NO_TLSv1;
 #endif
 #if SSL_OP_NO_TLSv1_1
             if (v > 1)
                 parsedOptions |= SSL_OP_NO_TLSv1_1;
 #endif
 #if SSL_OP_NO_TLSv1_2
@@ -226,40 +231,41 @@
     return t;
 }
 
 Security::ContextPtr
 Security::PeerOptions::createClientContext(bool setOptions)
 {
     Security::ContextPtr t = nullptr;
 
     updateTlsVersionLimits();
 
 #if USE_OPENSSL
     // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
     t = sslCreateClientContext(*this, (setOptions ? parsedOptions : 0), parsedFlags);
 
 #elif USE_GNUTLS && WHEN_READY_FOR_GNUTLS
     t = createBlankContext();
 
 #endif
 
     if (t) {
+        updateContextNpn(t);
         updateContextCa(t);
         updateContextCrl(t);
     }
 
     return t;
 }
 
 /// set of options we can parse and what they map to
 static struct ssl_option {
     const char *name;
     long value;
 
 } ssl_options[] = {
 
 #if SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
     {
         "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
     },
 #endif
 #if SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
@@ -506,40 +512,65 @@
 Security::PeerOptions::loadCrlFile()
 {
     parsedCrl.clear();
     if (crlFile.isEmpty())
         return;
 
 #if USE_OPENSSL
     BIO *in = BIO_new_file(crlFile.c_str(), "r");
     if (!in) {
         debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
         return;
     }
 
     while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL)) {
         parsedCrl.emplace_back(Security::CrlPointer(crl));
     }
     BIO_free(in);
 #endif
 }
 
+#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
+// Dummy next_proto_neg callback
+static int
+ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+{
+    static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
+    (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
+    return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+void
+Security::PeerOptions::updateContextNpn(Security::ContextPtr &ctx)
+{
+    if (flags.noTlsNpn)
+        return;
+
+#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
+    SSL_CTX_set_next_proto_select_cb(ctx, &ssl_next_proto_cb, nullptr);
+#endif
+
+    // NOTE: GnuTLS does not support the obsolete NPN extension.
+    //       it does support ALPN per-session, not per-context.
+}
+
 void
 Security::PeerOptions::updateContextCa(Security::ContextPtr &ctx)
 {
     debugs(83, 8, "Setting CA certificate locations.");
 
     for (auto i : caFiles) {
 #if USE_OPENSSL
         if (!SSL_CTX_load_verify_locations(ctx, i.c_str(), caDir.c_str())) {
             const int ssl_error = ERR_get_error();
             debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
         }
 #elif USE_GNUTLS
         if (gnutls_certificate_set_x509_trust_file(ctx, i.c_str(), GNUTLS_X509_FMT_PEM) < 0) {
             debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location: " << i);
         }
 #endif
     }
 
     if (flags.noDefaultCa)
         return;

=== modified file 'src/security/PeerOptions.h'
--- src/security/PeerOptions.h	2015-12-08 01:48:40 +0000
+++ src/security/PeerOptions.h	2015-12-15 23:21:30 +0000
@@ -23,80 +23,86 @@
 public:
     PeerOptions() : parsedOptions(0), parsedFlags(0), sslVersion(0), encryptTransport(false) {}
     PeerOptions(const PeerOptions &);
     virtual ~PeerOptions() = default;
 
     /// parse a TLS squid.conf option
     virtual void parse(const char *);
 
     /// reset the configuration details to default
     virtual void clear() {*this = PeerOptions();}
 
     /// generate an unset security context object
     virtual Security::ContextPtr createBlankContext() const;
 
     /// generate a security client-context from these configured options
     Security::ContextPtr createClientContext(bool setOptions);
 
     /// sync the context options with tls-min-version=N configuration
     void updateTlsVersionLimits();
 
+    /// setup the NPN extension details for the given context
+    void updateContextNpn(Security::ContextPtr &);
+
     /// setup the CA details for the given context
     void updateContextCa(Security::ContextPtr &);
 
     /// setup the CRL details for the given context
     void updateContextCrl(Security::ContextPtr &);
 
     /// output squid.conf syntax with 'pfx' prefix on parameters for the stored settings
     virtual void dumpCfg(Packable *, const char *pfx) const;
 
 private:
     long parseOptions();
     long parseFlags();
     void loadCrlFile();
 
 public:
     SBuf sslOptions;     ///< library-specific options string
     SBuf caDir;          ///< path of directory containing a set of trusted Certificate Authorities
     SBuf crlFile;        ///< path of file containing Certificate Revoke List
 
     SBuf sslCipher;
     SBuf sslFlags;       ///< flags defining what TLS operations Squid performs
     SBuf sslDomain;
 
     SBuf tlsMinVersion;  ///< version label for minimum TLS version to permit
 
     long parsedOptions; ///< parsed value of sslOptions
     long parsedFlags;   ///< parsed value of sslFlags
 
     std::list<Security::KeyData> certs; ///< details from the cert= and file= config parameters
     std::list<SBuf> caFiles;  ///< paths of files containing trusted Certificate Authority
     Security::CertRevokeList parsedCrl; ///< CRL to use when verifying the remote end certificate
 
 private:
     int sslVersion;
 
     /// flags governing Squid internal TLS operations
     struct flags_ {
-        flags_() : noDefaultCa(false) {}
+        flags_() : noDefaultCa(false), noTlsNpn(false) {}
 
         /// do not use the system default Trusted CA when verifying the remote end certificate
         bool noDefaultCa;
+
+        /// do not use the TLS NPN extension on these connections
+        bool noTlsNpn;
     } flags;
 
 public:
     /// whether transport encryption (TLS/SSL) is to be used on connections to the peer
     bool encryptTransport;
 };
 
 /// configuration options for DIRECT server access
 extern PeerOptions ProxyOutgoingConfig;
 
 } // namespace Security
 
 // parse the tls_outgoing_options directive
 void parse_securePeerOptions(Security::PeerOptions *);
 #define free_securePeerOptions(x) Security::ProxyOutgoingConfig.clear()
 #define dump_securePeerOptions(e,n,x) do { (e)->appendf(n); (x).dumpCfg((e),""); (e)->append("\n",1); } while(false)
 
 #endif /* SQUID_SRC_SECURITY_PEEROPTIONS_H */
 

=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc	2015-12-13 17:53:57 +0000
+++ src/ssl/support.cc	2015-12-15 23:15:30 +0000
@@ -605,51 +605,40 @@
         debugs(83, 5, "Comparing private and public SSL keys.");
 
         if (!SSL_CTX_check_private_key(sslContext)) {
             ssl_error = ERR_get_error();
             debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
                    keyfile << "': " << ERR_error_string(ssl_error, NULL));
             SSL_CTX_free(sslContext);
             return NULL;
         }
     */
 
     if (!configureSslContext(sslContext, port)) {
         debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
         SSL_CTX_free(sslContext);
         return NULL;
     }
 
     return sslContext;
 }
 
-#if defined(TLSEXT_TYPE_next_proto_neg)
-//Dummy next_proto_neg callback
-static int
-ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
-{
-    static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
-    (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
-    return SSL_TLSEXT_ERR_OK;
-}
-#endif
-
 Security::ContextPtr
 sslCreateClientContext(Security::PeerOptions &peer, long options, long fl)
 {
     Security::ContextPtr sslContext(peer.createBlankContext());
     if (!sslContext)
         return nullptr;
 
     SSL_CTX_set_options(sslContext, options);
 
 #if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
     SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
 #endif
 
     if (!peer.sslCipher.isEmpty()) {
         debugs(83, 5, "Using chiper suite " << peer.sslCipher << ".");
 
         const char *cipher = peer.sslCipher.c_str();
         if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
             const int ssl_error = ERR_get_error();
             fatalf("Failed to set SSL cipher suite '%s': %s\n",
@@ -682,43 +671,40 @@
         debugs(83, 5, "Comparing private and public SSL keys.");
 
         if (!SSL_CTX_check_private_key(sslContext)) {
             const int 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));
         }
     }
 
     debugs(83, 9, "Setting RSA key generation callback.");
     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
 
     if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
         debugs(83, 2, "NOTICE: Peer certificates are not verified for validity!");
         SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
     } else {
         debugs(83, 9, "Setting certificate verification callback.");
         SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
     }
 
-#if defined(TLSEXT_TYPE_next_proto_neg)
-    SSL_CTX_set_next_proto_select_cb(sslContext, &ssl_next_proto_cb, NULL);
-#endif
     return sslContext;
 }
 
 /// \ingroup ServerProtocolSSLInternal
 int
 ssl_read_method(int fd, char *buf, int len)
 {
     SSL *ssl = fd_table[fd].ssl;
     int i;
 
 #if DONT_DO_THIS
 
     if (!SSL_is_init_finished(ssl)) {
         errno = ENOTCONN;
         return -1;
     }
 
 #endif
 
     i = SSL_read(ssl, buf, len);



More information about the squid-dev mailing list