]>
Commit | Line | Data |
---|---|---|
a27cfbe0 | 1 | #!@PERL@ |
a1f04d64 AR |
2 | |
3 | use warnings; | |
4a77bb4e CT |
4 | use strict; |
5 | use Getopt::Long; | |
6 | use Pod::Usage; | |
a1f04d64 AR |
7 | use Crypt::OpenSSL::X509; |
8 | use FileHandle; | |
4a77bb4e CT |
9 | use POSIX qw(strftime); |
10 | ||
11 | my $debug = 0; | |
12 | my $help = 0; | |
13 | ||
14 | =pod | |
15 | ||
16 | =head1 NAME | |
17 | ||
bbf79f12 | 18 | security_fake_certverify - A fake cert validation helper for Squid |
4a77bb4e CT |
19 | |
20 | =head1 SYNOPSIS | |
21 | ||
bbf79f12 | 22 | security_fake_certverify [-d | --debug] [-h | --help] |
4a77bb4e | 23 | |
8311b837 AJ |
24 | =head1 DESCRIPTION |
25 | ||
26 | Retrieves the SSL certificate error list from Squid and echo back without any change. | |
27 | ||
28 | =head1 OPTIONS | |
29 | ||
4a77bb4e CT |
30 | =over 8 |
31 | ||
32 | =item B<-h | --help> | |
33 | ||
34 | brief help message | |
35 | ||
36 | =item B<-d | --debug> | |
37 | ||
38 | enable debug messages to stderr | |
39 | ||
40 | =back | |
a1f04d64 | 41 | |
8311b837 | 42 | =head1 AUTHOR |
a1f04d64 | 43 | |
8311b837 AJ |
44 | This program and documentation was written by |
45 | I<Christos Tsantilas <chtsanti@users.sourceforge.net>> | |
4a77bb4e CT |
46 | |
47 | =head1 COPYRIGHT | |
48 | ||
b8ae064d | 49 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
ca02e0ec AJ |
50 | * |
51 | * Squid software is distributed under GPLv2+ license and includes | |
52 | * contributions from numerous individuals and organizations. | |
53 | * Please see the COPYING and CONTRIBUTORS files for details. | |
54 | ||
4a77bb4e CT |
55 | (C) 2012 The Measurement Factory, Author: Tsantilas Christos |
56 | ||
57 | This program is free software. You may redistribute copies of it under the | |
58 | terms of the GNU General Public License version 2, or (at your opinion) any | |
59 | later version. | |
60 | ||
8311b837 AJ |
61 | =head1 QUESTIONS |
62 | ||
63 | Questions on the usage of this program can be sent to the I<Squid Users mailing list <squid-users@lists.squid-cache.org>> | |
64 | ||
65 | =head1 REPORTING BUGS | |
66 | ||
67 | Bug reports need to be made in English. | |
68 | See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report. | |
69 | ||
70 | Report bugs or bug fixes using http://bugs.squid-cache.org/ | |
71 | ||
72 | Report serious security bugs to I<Squid Bugs <squid-bugs@lists.squid-cache.org>> | |
73 | ||
74 | Report ideas for new improvements to the I<Squid Developers mailing list <squid-dev@lists.squid-cache.org>> | |
75 | ||
76 | =head1 SEE ALSO | |
77 | ||
78 | squid (8), GPL (7), | |
79 | ||
80 | The Squid FAQ wiki http://wiki.squid-cache.org/SquidFaq | |
81 | ||
82 | The Squid Configuration Manual http://www.squid-cache.org/Doc/config/ | |
83 | ||
4a77bb4e CT |
84 | =cut |
85 | ||
86 | GetOptions( | |
87 | 'help' => \$help, | |
88 | 'debug' => \$debug, | |
89 | ) or pod2usage(1); | |
90 | ||
91 | pod2usage(1) if ($help); | |
a1f04d64 AR |
92 | |
93 | $|=1; | |
94 | while (<>) { | |
95 | my $first_line = $_; | |
96 | my @line_args = split; | |
97 | ||
98 | if ($first_line =~ /^\s*$/) { | |
99 | next; | |
100 | } | |
101 | ||
102 | my $response; | |
dd7167ea | 103 | my $haserror = 0; |
4a77bb4e CT |
104 | my $channelId = $line_args[0]; |
105 | my $code = $line_args[1]; | |
106 | my $bodylen = $line_args[2]; | |
107 | my $body = $line_args[3] . "\n"; | |
108 | if ($channelId !~ /\d+/) { | |
109 | $response = $channelId." BH message=\"This helper is concurrent and requires the concurrency option to be specified.\"\1"; | |
110 | } elsif ($bodylen !~ /\d+/) { | |
111 | $response = $channelId." BH message=\"cert validator request syntax error \" \1"; | |
112 | } else { | |
a1f04d64 AR |
113 | my $readlen = length($body); |
114 | my %certs = (); | |
62a7607e | 115 | my %errors = (); |
a1f04d64 AR |
116 | my @responseErrors = (); |
117 | ||
118 | while($readlen < $bodylen) { | |
47f28373 | 119 | my $t = <>; |
a1f04d64 AR |
120 | if (defined $t) { |
121 | $body = $body . $t; | |
122 | $readlen = length($body); | |
123 | } | |
124 | } | |
125 | ||
4a77bb4e CT |
126 | print(STDERR logPrefix()."GOT ". "Code=".$code." $bodylen \n") if ($debug); #.$body; |
127 | my $hostname; | |
6e325882 CT |
128 | my $sslVersion = "-"; |
129 | my $sslCipher = "-"; | |
130 | parseRequest($body, \$hostname, \$sslVersion, \$sslCipher, \%errors, \%certs); | |
4a77bb4e CT |
131 | print(STDERR logPrefix()."Parse result: \n") if ($debug); |
132 | print(STDERR logPrefix()."\tFOUND host:".$hostname."\n") if ($debug); | |
6e325882 CT |
133 | print(STDERR logPrefix()."\tFOUND ssl version:".$sslVersion."\n") if ($debug); |
134 | print(STDERR logPrefix()."\tFOUND ssl cipher:".$sslCipher."\n") if ($debug); | |
4a77bb4e | 135 | print(STDERR logPrefix()."\tFOUND ERRORS:") if ($debug); |
62a7607e CT |
136 | foreach my $err (keys %errors) { |
137 | print(STDERR logPrefix().$errors{$err}{"name"}."/".$errors{$err}{"cert"}." ,") if ($debug); | |
a1f04d64 | 138 | } |
4a77bb4e CT |
139 | print(STDERR "\n") if ($debug); |
140 | foreach my $key (keys %certs) { | |
a1f04d64 | 141 | ## Use "perldoc Crypt::OpenSSL::X509" for X509 available methods. |
4a77bb4e | 142 | print(STDERR logPrefix()."\tFOUND cert ".$key.": ".$certs{$key}->subject() . "\n") if ($debug); |
a1f04d64 AR |
143 | } |
144 | ||
47f28373 | 145 | #got the peer certificate ID. Assume that the peer certificate is the first one. |
a1f04d64 AR |
146 | my $peerCertId = (keys %certs)[0]; |
147 | ||
47f28373 | 148 | # Echo back the errors: fill the responseErrors array with the errors we read. |
62a7607e | 149 | foreach my $err (keys %errors) { |
dd7167ea | 150 | $haserror = 1; |
47f28373 FC |
151 | appendError (\@responseErrors, |
152 | $errors{$err}{"name"}, #The error name | |
153 | "Checked by Cert Validator", # An error reason | |
154 | $errors{$err}{"cert"} # The cert ID. We are always filling with the peer certificate. | |
a1f04d64 AR |
155 | ); |
156 | } | |
157 | ||
158 | $response = createResponse(\@responseErrors); | |
159 | my $len = length($response); | |
dd7167ea | 160 | if ($haserror) { |
4a77bb4e | 161 | $response = $channelId." ERR ".$len." ".$response."\1"; |
dd7167ea | 162 | } else { |
4a77bb4e | 163 | $response = $channelId." OK ".$len." ".$response."\1"; |
dd7167ea | 164 | } |
a1f04d64 AR |
165 | } |
166 | ||
167 | print $response; | |
4a77bb4e | 168 | print(STDERR logPrefix().">> ".$response."\n") if ($debug); |
a1f04d64 | 169 | } |
a1f04d64 AR |
170 | |
171 | sub trim | |
172 | { | |
173 | my $s = shift; | |
174 | $s =~ s/^\s+//; | |
175 | $s =~ s/\s+$//; | |
176 | return $s; | |
177 | } | |
178 | ||
179 | sub appendError | |
180 | { | |
181 | my ($errorArrays) = shift; | |
182 | my($errorName) = shift; | |
183 | my($errorReason) = shift; | |
184 | my($errorCert) = shift; | |
185 | push @$errorArrays, { "error_name" => $errorName, "error_reason" => $errorReason, "error_cert" => $errorCert}; | |
186 | } | |
187 | ||
188 | sub createResponse | |
189 | { | |
190 | my ($responseErrors) = shift; | |
191 | my $response=""; | |
192 | my $i = 0; | |
4a77bb4e | 193 | foreach my $err (@$responseErrors) { |
a1f04d64 AR |
194 | $response=$response."error_name_".$i."=".$err->{"error_name"}."\n". |
195 | "error_reason_".$i."=".$err->{"error_reason"}."\n". | |
196 | "error_cert_".$i."=".$err->{"error_cert"}."\n"; | |
197 | $i++; | |
198 | } | |
199 | return $response; | |
200 | } | |
201 | ||
202 | sub parseRequest | |
203 | { | |
204 | my($request)=shift; | |
205 | my $hostname = shift; | |
6e325882 CT |
206 | my $sslVersion = shift; |
207 | my $sslCipher = shift; | |
a1f04d64 AR |
208 | my $errors = shift; |
209 | my $certs = shift; | |
210 | while ($request !~ /^\s*$/) { | |
211 | $request = trim($request); | |
212 | if ($request =~ /^host=/) { | |
213 | my($vallen) = index($request, "\n"); | |
214 | my $host = substr($request, 5, $vallen - 5); | |
215 | $$hostname = $host; | |
721fabb6 | 216 | $request =~ s/^host=.*$//m; |
a1f04d64 | 217 | } |
6e325882 CT |
218 | if ($request =~ s/^proto_version=(.*?)$//m) { |
219 | $$sslVersion = $1; | |
220 | } | |
221 | if ($request =~ s/^cipher=(.*?)$//m) { | |
222 | $$sslCipher = $1; | |
223 | } | |
62a7607e | 224 | if ($request =~ /^cert_(\d+)=/) { |
a1f04d64 AR |
225 | my $certId = "cert_".$1; |
226 | my($vallen) = index($request, "-----END CERTIFICATE-----") + length("-----END CERTIFICATE-----"); | |
227 | my $x509 = Crypt::OpenSSL::X509->new_from_string(substr($request, index($request, "-----BEGIN"))); | |
228 | $certs->{$certId} = $x509; | |
229 | $request = substr($request, $vallen); | |
230 | } | |
62a7607e CT |
231 | elsif ($request =~ /^error_name_(\d+)=(.*)$/m) { |
232 | my $errorId = $1; | |
233 | my $errorName = $2; | |
234 | $request =~ s/^error_name_\d+=.*$//m; | |
235 | $errors->{$errorId}{"name"} = $errorName; | |
236 | } | |
237 | elsif ($request =~ /^error_cert_(\d+)=(.*)$/m) { | |
238 | my $errorId = $1; | |
239 | my $certId = $2; | |
240 | $request =~ s/^error_cert_\d+=.*$//m; | |
241 | $errors->{$errorId}{"cert"} = $certId; | |
242 | } | |
a1f04d64 | 243 | else { |
4a77bb4e | 244 | print(STDERR logPrefix()."ParseError on \"".$request."\"\n") if ($debug); |
a1f04d64 AR |
245 | $request = "";# finish processing.... |
246 | } | |
247 | } | |
248 | } | |
4a77bb4e CT |
249 | |
250 | ||
251 | sub logPrefix | |
252 | { | |
47f28373 | 253 | return strftime("%Y/%m/%d %H:%M:%S.0", localtime)." ".$0." ".$$." | " ; |
4a77bb4e | 254 | } |