> 
> It looks like this question has come up before, but I'm hoping to get some
> further details on it.
> 
> I've used a couple of firewalls (Watchguard & Fortigate) that allow me to do a
> level of HTTPS site filtering without decryption. I believe that it works by
> requesting and examining the certificate sent from the remote server. If the
> subject name or subject alternate names on the certificate match a whitelist
> of domains that we have specified then access to the site is allowed. As far 
> as
> I know, it does not require decrypting the SSL connection and I'm positive
> that it doesn't return self generated certificates.
> 
> It would not be very effective for someone trying to use Squid for blocking
> end users access to every site on the Internet. But, it works great for our 
> use
> case where we want to allow our servers to only access a handful of sites.
> 
> From everything I've read, it looks like the only option is for Squid to 
> decrypt
> the connection. Is there a particular reason why this feature could not be
> implemented in Squid if it's available in these other devices? Or if it is
> available, could I get some direction.
> 

I assume you are doing this for transparent proxying, otherwise you already 
have the hostname the user is trying to access, which is better than the cert 
name.

You could wait for this http://wiki.squid-cache.org/Features/SslPeekAndSplice 
which might eventually be able to do what you want.

In the meantime, you could try using an external acl. I didn't have a lot of 
luck... it works but has some limitations. Basically I threw together some php 
(see end of email), then used the following configuration:

# actual cert doesn't matter as it isn't used, but squid insists on it being 
there
https_port 0.0.0.0:33129 intercept name=transparentssl 
cert=/etc/squid/dummy.pem ssl-bump
...
ssl_bump none all
...
external_acl_type check_ssl %DST %PORT /usr/lib/squid3/check_ssl_cert_name
...
acl ssl_bad external check_ssl facebook.com
...
http_access deny transproxyssl ssl_bad
deny_info TCP_RESET transproxyssl

That's blacklist, not whitelist, but easy enough to invert. The problem I had 
is that I couldn't find a way to specify multiple 'acl ssl_bad external ...' 
lines, so you'd need a different acl + http_access for every certificate name 
you wanted to check against.

You'll find cases that will cause you trouble though, eg the certificate for 
"google.com" is also for "youtube.com", so you can't allow one without allowing 
the other.

About the code - I basically just threw it together using a few examples of ssl 
cert identification that google found for me. I don't sanitise any input. It 
almost certainly leaks memory and doesn't handle error conditions well, or at 
all. And the actual comparison to the value being tested is very basic. And I 
make the assumption that the certificate has a san, and that the cn is in the 
san list, which isn't always correct. Hopefully you will derive some 
inspiration from it though. One additional thing it could do is log the cn to 
the logfile - append "log=$cn" to the OK or ERR output, then use %ea (I think) 
in the squid log directive to log that value. Also PHP is probably a poor 
choice of language - I don't really know PHP it just happened to be the 
language my google search returned the best examples in.

I think squid caches the result of the external acl so performance shouldn't be 
too bad. If squid didn't cache the result you'd probably need to build some 
caching yourself otherwise it would do a callout every time.

James

#!/usr/bin/php
<?
stream_set_timeout(STDIN, -1);
while (!feof(STDIN)) {
  $line = trim(fgets(STDIN));
  if (substr_count($line, ' ') < 1) {
    continue;
  }
  $params = explode(' ', $line);
  $host = $params[0];
  $port = $params[1];
  $test = $params[2];

  $g = stream_context_create (array("ssl" => array("capture_peer_cert" => 
true)));
  $r = stream_socket_client("ssl://$host:$port", $errno, $errstr, 30, 
STREAM_CLIENT_CONNECT, $g);
  $cont = stream_context_get_params($r);
  $cert = openssl_x509_parse($cont["options"]["ssl"]["peer_certificate"]);
  $cn = $cert["subject"]["CN"];
  $san = $cert["extensions"]["subjectAltName"];
  $match = false;
  foreach (explode(', ', $san) as $name) {
    if (substr($name, -strlen($test)) == $test) {
      $match = true;
      break;
    }
  }
  if ($match) {
    fwrite(STDOUT, "OK\n");
  } else {
    fwrite(STDOUT, "ERR\n");
  }
}
?>

_______________________________________________
squid-users mailing list
squid-users@lists.squid-cache.org
http://lists.squid-cache.org/listinfo/squid-users

Reply via email to