#
use warnings;
-# TODO:
-# use strict;
-
+use strict;
+use Getopt::Long;
+use Pod::Usage;
use Crypt::OpenSSL::X509;
use FileHandle;
+use POSIX qw(strftime);
+
+my $debug = 0;
+my $help = 0;
+
+=pod
+
+=head1 NAME
+
+cert_valid.pl - A fake cert validation helper for Squid
+
+=head1 SYNOPSIS
+
+cert_valid.pl [-d | --debug] [-h | --help]
+
+=over 8
+
+=item B<-h | --help>
+
+brief help message
+
+=item B<-d | --debug>
+
+enable debug messages to stderr
+
+=back
+
+=head1 DESCRIPTION
+
+Retrieves the SSL certificate error list from squid and echo back without any change.
-my $LOGFILE = "/tmp/ssl_cert_valid.log";
+=head1 COPYRIGHT
-open(LOG, ">>$LOGFILE") or die("Cannot open logfile $LOGFILE, stopped");
-LOG->autoflush(1);
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+
+(C) 2012 The Measurement Factory, Author: Tsantilas Christos
+
+This program is free software. You may redistribute copies of it under the
+terms of the GNU General Public License version 2, or (at your opinion) any
+later version.
+
+=cut
+
+GetOptions(
+ 'help' => \$help,
+ 'debug' => \$debug,
+ ) or pod2usage(1);
+
+pod2usage(1) if ($help);
$|=1;
while (<>) {
my $response;
my $haserror = 0;
- my $code = $line_args[0];
- my $bodylen = $line_args[1];
- my $body = $line_args[2] . "\n";
- if ($bodylen =~ /\d+/) {
+ my $channelId = $line_args[0];
+ my $code = $line_args[1];
+ my $bodylen = $line_args[2];
+ my $body = $line_args[3] . "\n";
+ if ($channelId !~ /\d+/) {
+ $response = $channelId." BH message=\"This helper is concurrent and requires the concurrency option to be specified.\"\1";
+ } elsif ($bodylen !~ /\d+/) {
+ $response = $channelId." BH message=\"cert validator request syntax error \" \1";
+ } else {
my $readlen = length($body);
my %certs = ();
- my @errors = ();
+ my %errors = ();
my @responseErrors = ();
while($readlen < $bodylen) {
}
}
- print LOG "GOT ". "Code=".$code." $bodylen \n"; #.$body;
- parseRequest($body, \$hostname, \@errors, \%certs);
- print LOG " Parse result: \n";
- print LOG "\tFOUND host:".$hostname."\n";
- print LOG "\tFOUND ERRORS:";
- foreach $err(@errors) {
- print LOG "$err ,";
+ print(STDERR logPrefix()."GOT ". "Code=".$code." $bodylen \n") if ($debug); #.$body;
+ my $hostname;
+ my $sslVersion = "-";
+ my $sslCipher = "-";
+ parseRequest($body, \$hostname, \$sslVersion, \$sslCipher, \%errors, \%certs);
+ print(STDERR logPrefix()."Parse result: \n") if ($debug);
+ print(STDERR logPrefix()."\tFOUND host:".$hostname."\n") if ($debug);
+ print(STDERR logPrefix()."\tFOUND ssl version:".$sslVersion."\n") if ($debug);
+ print(STDERR logPrefix()."\tFOUND ssl cipher:".$sslCipher."\n") if ($debug);
+ print(STDERR logPrefix()."\tFOUND ERRORS:") if ($debug);
+ foreach my $err (keys %errors) {
+ print(STDERR logPrefix().$errors{$err}{"name"}."/".$errors{$err}{"cert"}." ,") if ($debug);
}
- print LOG "\n";
- foreach $key (keys %certs) {
+ print(STDERR "\n") if ($debug);
+ foreach my $key (keys %certs) {
## Use "perldoc Crypt::OpenSSL::X509" for X509 available methods.
- print LOG "\tFOUND cert ".$key.": ".$certs{$key}->subject() . "\n";
+ print(STDERR logPrefix()."\tFOUND cert ".$key.": ".$certs{$key}->subject() . "\n") if ($debug);
}
#got the peer certificate ID. Assume that the peer certificate is the first one.
my $peerCertId = (keys %certs)[0];
# Echo back the errors: fill the responseErrors array with the errors we read.
- foreach $err (@errors) {
+ foreach my $err (keys %errors) {
$haserror = 1;
appendError (\@responseErrors,
- $err, #The error name
+ $errors{$err}{"name"}, #The error name
"Checked by Cert Validator", # An error reason
- $peerCertId # The cert ID. We are always filling with the peer certificate.
+ $errors{$err}{"cert"} # The cert ID. We are always filling with the peer certificate.
);
}
$response = createResponse(\@responseErrors);
my $len = length($response);
if ($haserror) {
- $response = "ERR ".$len." ".$response."\1";
+ $response = $channelId." ERR ".$len." ".$response."\1";
} else {
- $response = "OK ".$len." ".$response."\1";
+ $response = $channelId." OK ".$len." ".$response."\1";
}
- } else {
- $response = "BH 0 \1";
}
print $response;
- print LOG ">> ".$response;
+ print(STDERR logPrefix().">> ".$response."\n") if ($debug);
}
-close(LOG);
sub trim
{
my ($responseErrors) = shift;
my $response="";
my $i = 0;
- foreach $err (@$responseErrors) {
+ foreach my $err (@$responseErrors) {
$response=$response."error_name_".$i."=".$err->{"error_name"}."\n".
"error_reason_".$i."=".$err->{"error_reason"}."\n".
"error_cert_".$i."=".$err->{"error_cert"}."\n";
{
my($request)=shift;
my $hostname = shift;
+ my $sslVersion = shift;
+ my $sslCipher = shift;
my $errors = shift;
my $certs = shift;
while ($request !~ /^\s*$/) {
my($vallen) = index($request, "\n");
my $host = substr($request, 5, $vallen - 5);
$$hostname = $host;
- $request =~ s/^host=.*\n//;
+ $request =~ s/^host=.*$//m;
}
- if ($request =~ /^errors=/) {
- my($vallen) = index($request, "\n");
- my $listerrors = substr($request, 7, $vallen - 7);
- @$errors = split /,/, $listerrors;
- $request =~ s/^errors=.*\n//;
+ if ($request =~ s/^proto_version=(.*?)$//m) {
+ $$sslVersion = $1;
}
- elsif ($request =~ /^cert_(\d+)=/) {
+ if ($request =~ s/^cipher=(.*?)$//m) {
+ $$sslCipher = $1;
+ }
+ if ($request =~ /^cert_(\d+)=/) {
my $certId = "cert_".$1;
my($vallen) = index($request, "-----END CERTIFICATE-----") + length("-----END CERTIFICATE-----");
my $x509 = Crypt::OpenSSL::X509->new_from_string(substr($request, index($request, "-----BEGIN")));
$certs->{$certId} = $x509;
$request = substr($request, $vallen);
}
+ elsif ($request =~ /^error_name_(\d+)=(.*)$/m) {
+ my $errorId = $1;
+ my $errorName = $2;
+ $request =~ s/^error_name_\d+=.*$//m;
+ $errors->{$errorId}{"name"} = $errorName;
+ }
+ elsif ($request =~ /^error_cert_(\d+)=(.*)$/m) {
+ my $errorId = $1;
+ my $certId = $2;
+ $request =~ s/^error_cert_\d+=.*$//m;
+ $errors->{$errorId}{"cert"} = $certId;
+ }
else {
- print LOG "ParseError on \"".$request."\"\n";
+ print(STDERR logPrefix()."ParseError on \"".$request."\"\n") if ($debug);
$request = "";# finish processing....
}
}
}
+
+
+sub logPrefix
+{
+ return strftime("%Y/%m/%d %H:%M:%S.0", localtime)." ".$0." ".$$." | " ;
+}