line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# $Id$ |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# client::ssl Brik |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
package Metabrik::Client::Ssl; |
7
|
1
|
|
|
1
|
|
851
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
8
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
28
|
|
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
5
|
use base qw(Metabrik); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2884
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub brik_properties { |
13
|
|
|
|
|
|
|
return { |
14
|
0
|
|
|
0
|
1
|
|
revision => '$Revision$', |
15
|
|
|
|
|
|
|
tags => [ qw(unstable tls) ], |
16
|
|
|
|
|
|
|
author => 'GomoR ', |
17
|
|
|
|
|
|
|
license => 'http://opensource.org/licenses/BSD-3-Clause', |
18
|
|
|
|
|
|
|
attributes => { |
19
|
|
|
|
|
|
|
uri => [ qw(uri) ], |
20
|
|
|
|
|
|
|
}, |
21
|
|
|
|
|
|
|
commands => { |
22
|
|
|
|
|
|
|
install => [ ], # Inherited |
23
|
|
|
|
|
|
|
verify_server => [ qw(uri|OPTIONAL) ], |
24
|
|
|
|
|
|
|
getcertificate => [ qw(uri|OPTIONAL) ], |
25
|
|
|
|
|
|
|
getcertificate2 => [ qw(host port) ], |
26
|
|
|
|
|
|
|
}, |
27
|
|
|
|
|
|
|
require_modules => { |
28
|
|
|
|
|
|
|
'Data::Dumper' => [ ], |
29
|
|
|
|
|
|
|
'IO::Socket::SSL' => [ ], |
30
|
|
|
|
|
|
|
'LWP::UserAgent' => [ ], |
31
|
|
|
|
|
|
|
'LWP::ConnCache' => [ ], |
32
|
|
|
|
|
|
|
'URI' => [ ], |
33
|
|
|
|
|
|
|
'Net::SSLeay' => [ ], |
34
|
|
|
|
|
|
|
'Metabrik::String::Uri' => [ ], |
35
|
|
|
|
|
|
|
}, |
36
|
|
|
|
|
|
|
need_packages => { |
37
|
|
|
|
|
|
|
ubuntu => [ qw(libssl-dev) ], |
38
|
|
|
|
|
|
|
debian => [ qw(libssl-dev) ], |
39
|
|
|
|
|
|
|
kali => [ qw(libssl-dev) ], |
40
|
|
|
|
|
|
|
centos => [ qw(openssl-devel) ], |
41
|
|
|
|
|
|
|
redhat => [ qw(openssl-devel) ], |
42
|
|
|
|
|
|
|
}, |
43
|
|
|
|
|
|
|
}; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub verify_server { |
47
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
48
|
0
|
|
|
|
|
|
my ($uri) = @_; |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
0
|
|
|
|
$uri ||= $self->uri; |
51
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('verify_server', $uri) or return; |
52
|
|
|
|
|
|
|
|
53
|
0
|
0
|
|
|
|
|
my $su = Metabrik::String::Uri->new_from_brik_init($self) or return; |
54
|
0
|
0
|
|
|
|
|
my $parsed = $su->parse($uri) or return; |
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
my $host = $parsed->{host}; |
57
|
0
|
|
|
|
|
|
my $port = $parsed->{port}; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
$self->log->debug("verify_server: trying host [".$parsed->{host}."] ". |
60
|
0
|
|
|
|
|
|
"with port [".$parsed->{port}."]"); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my $client = IO::Socket::SSL->new( |
63
|
|
|
|
|
|
|
PeerHost => $parsed->{host}, |
64
|
|
|
|
|
|
|
PeerPort => $parsed->{port}, |
65
|
|
|
|
|
|
|
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_PEER(), |
66
|
|
|
|
|
|
|
SSL_verifycn_name => $parsed->{host}, |
67
|
0
|
|
|
|
|
|
SSL_verifycn_scheme => 'http', |
68
|
|
|
|
|
|
|
); |
69
|
0
|
0
|
0
|
|
|
|
if (! defined($client) && ! length($!)) { |
|
|
0
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
$self->log->verbose("verify_server: not verified: [". |
71
|
|
|
|
|
|
|
$IO::Socket::SSL::SSL_ERROR."]"); |
72
|
0
|
|
|
|
|
|
return 0; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
elsif (! defined($client)) { |
75
|
0
|
|
|
|
|
|
return $self->log->error("verify_server: connection failed with ". |
76
|
|
|
|
|
|
|
"error: [$!]"); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$self->log->verbose("verify_server: verified"); |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
return 1; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# |
85
|
|
|
|
|
|
|
# Note: works only with IO::Socket::SSL, not with Net::SSL (using Crypt::SSLeay) |
86
|
|
|
|
|
|
|
# |
87
|
|
|
|
|
|
|
sub getcertificate { |
88
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
89
|
0
|
|
|
|
|
|
my ($uri) = @_; |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
0
|
|
|
|
$uri ||= $self->uri; |
92
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('getcertificate', $uri) or return; |
93
|
|
|
|
|
|
|
|
94
|
0
|
0
|
|
|
|
|
if ($uri !~ /^https:\/\//) { |
95
|
0
|
|
|
|
|
|
return $self->log->error("must use https to get a certificate"); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
my $ua = LWP::UserAgent->new( |
99
|
|
|
|
|
|
|
#ssl_opts => { verify_hostname => 0 }, # will do manual check |
100
|
|
|
|
|
|
|
ssl_opts => { SSL_verify_mode => 'SSL_VERIFY_NONE'}, |
101
|
|
|
|
|
|
|
); |
102
|
0
|
|
0
|
|
|
|
$ua->timeout(defined($self->global) && $self->global->rtimeout || 3); |
103
|
0
|
|
|
|
|
|
$ua->max_redirect(0); |
104
|
0
|
|
|
|
|
|
$ua->env_proxy; |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
my $cache = LWP::ConnCache->new; |
107
|
0
|
|
|
|
|
|
$ua->conn_cache($cache); |
108
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
my $response = $ua->get($uri); |
110
|
|
|
|
|
|
|
# XXX: we ignore response? |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
my $cc = $ua->conn_cache->{cc_conns}; |
113
|
0
|
0
|
|
|
|
|
if (! defined($cc)) { |
114
|
0
|
|
|
|
|
|
return $self->log->error("unable to retrieve connection cache"); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
|
if (scalar(@$cc) == 0) { |
118
|
0
|
|
|
|
|
|
return $self->log->error("getcertificate: no connection cached"); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
my $sock = $cc->[0][0]; |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my %info = (); |
124
|
|
|
|
|
|
|
# peer_certificate from IO::Socket::SSL/Crypt::SSLeay |
125
|
0
|
0
|
|
|
|
|
if ($sock->can('peer_certificate')) { |
126
|
0
|
|
|
|
|
|
my $authority = $sock->peer_certificate('authority'); # issuer |
127
|
0
|
|
|
|
|
|
my $owner = $sock->peer_certificate('owner'); # subject |
128
|
0
|
|
|
|
|
|
my $commonName = $sock->peer_certificate('commonName'); # cn |
129
|
0
|
|
|
|
|
|
my $subjectAltNames = $sock->peer_certificate('subjectAltNames'); |
130
|
0
|
|
|
|
|
|
my $sslversion = $sock->get_sslversion; |
131
|
0
|
|
|
|
|
|
my $cipher = $sock->get_cipher; |
132
|
0
|
|
|
|
|
|
my $servername = $sock->get_servername; # Only when SNI is used |
133
|
|
|
|
|
|
|
#my $verify_hostname = $sock->verify_hostname('hostname', 'http'); |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
$info{authority} = $authority; |
136
|
0
|
|
|
|
|
|
$info{owner} = $owner; |
137
|
0
|
|
|
|
|
|
$info{commonName} = $commonName; |
138
|
0
|
|
|
|
|
|
$info{subjectAltNames} = $subjectAltNames; |
139
|
0
|
|
|
|
|
|
$info{sslversion} = $sslversion; |
140
|
0
|
|
|
|
|
|
$info{cipher} = $cipher; |
141
|
0
|
|
|
|
|
|
$info{servername} = $servername; |
142
|
|
|
|
|
|
|
#$info{verify_hostname} = $verify_hostname; |
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
print Data::Dumper::Dumper(\%info)."\n"; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
else { |
147
|
0
|
|
|
|
|
|
return $self->log->error("socket [$sock] cannot do 'peer_certificate'"); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
#$sock->stop_SSL; |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
return $sock; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
1
|
|
|
1
|
|
781
|
eval("use Net::SSLeay qw/XN_FLAG_RFC2253 ASN1_STRFLGS_ESC_MSB/;"); |
|
1
|
|
|
|
|
12257
|
|
|
1
|
|
|
|
|
466
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Taken from http://cpansearch.perl.org/src/MIKEM/Net-SSLeay-1.57/examples/x509_cert_details.pl |
158
|
|
|
|
|
|
|
sub get_cert_details { |
159
|
0
|
|
|
0
|
0
|
|
my $x509 = shift; |
160
|
0
|
|
|
|
|
|
my $rv = {}; |
161
|
0
|
|
|
|
|
|
my $flag_rfc22536_utf8 = (Net::SSLeay::XN_FLAG_RFC2253()) & (~ Net::SSLeay::ASN1_STRFLGS_ESC_MSB()); |
162
|
|
|
|
|
|
|
|
163
|
0
|
0
|
|
|
|
|
die 'ERROR: $x509 is NULL, gonna quit' unless $x509; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
#warn "Info: dumping subject\n"; |
166
|
0
|
|
|
|
|
|
my $subj_name = Net::SSLeay::X509_get_subject_name($x509); |
167
|
0
|
|
|
|
|
|
my $subj_count = Net::SSLeay::X509_NAME_entry_count($subj_name); |
168
|
0
|
|
|
|
|
|
$rv->{subject}->{count} = $subj_count; |
169
|
0
|
|
|
|
|
|
$rv->{subject}->{oneline} = Net::SSLeay::X509_NAME_oneline($subj_name); |
170
|
0
|
|
|
|
|
|
$rv->{subject}->{print_rfc2253} = Net::SSLeay::X509_NAME_print_ex($subj_name); |
171
|
0
|
|
|
|
|
|
$rv->{subject}->{print_rfc2253_utf8} = Net::SSLeay::X509_NAME_print_ex($subj_name, $flag_rfc22536_utf8); |
172
|
0
|
|
|
|
|
|
$rv->{subject}->{print_rfc2253_utf8_decoded} = Net::SSLeay::X509_NAME_print_ex($subj_name, $flag_rfc22536_utf8, 1); |
173
|
0
|
|
|
|
|
|
for my $i (0..$subj_count-1) { |
174
|
0
|
|
|
|
|
|
my $entry = Net::SSLeay::X509_NAME_get_entry($subj_name, $i); |
175
|
0
|
|
|
|
|
|
my $asn1_string = Net::SSLeay::X509_NAME_ENTRY_get_data($entry); |
176
|
0
|
|
|
|
|
|
my $asn1_object = Net::SSLeay::X509_NAME_ENTRY_get_object($entry); |
177
|
0
|
|
|
|
|
|
my $nid = Net::SSLeay::OBJ_obj2nid($asn1_object); |
178
|
0
|
0
|
|
|
|
|
$rv->{subject}->{entries}->[$i] = { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
179
|
|
|
|
|
|
|
oid => Net::SSLeay::OBJ_obj2txt($asn1_object,1), |
180
|
|
|
|
|
|
|
data => Net::SSLeay::P_ASN1_STRING_get($asn1_string), |
181
|
|
|
|
|
|
|
data_utf8_decoded => Net::SSLeay::P_ASN1_STRING_get($asn1_string, 1), |
182
|
|
|
|
|
|
|
nid => ($nid>0) ? $nid : undef, |
183
|
|
|
|
|
|
|
ln => ($nid>0) ? Net::SSLeay::OBJ_nid2ln($nid) : undef, |
184
|
|
|
|
|
|
|
sn => ($nid>0) ? Net::SSLeay::OBJ_nid2sn($nid) : undef, |
185
|
|
|
|
|
|
|
}; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
#warn "Info: dumping issuer\n"; |
189
|
0
|
|
|
|
|
|
my $issuer_name = Net::SSLeay::X509_get_issuer_name($x509); |
190
|
0
|
|
|
|
|
|
my $issuer_count = Net::SSLeay::X509_NAME_entry_count($issuer_name); |
191
|
0
|
|
|
|
|
|
$rv->{issuer}->{count} = $issuer_count; |
192
|
0
|
|
|
|
|
|
$rv->{issuer}->{oneline} = Net::SSLeay::X509_NAME_oneline($issuer_name); |
193
|
0
|
|
|
|
|
|
$rv->{issuer}->{print_rfc2253} = Net::SSLeay::X509_NAME_print_ex($issuer_name); |
194
|
0
|
|
|
|
|
|
$rv->{issuer}->{print_rfc2253_utf8} = Net::SSLeay::X509_NAME_print_ex($issuer_name, $flag_rfc22536_utf8); |
195
|
0
|
|
|
|
|
|
$rv->{issuer}->{print_rfc2253_utf8_decoded} = Net::SSLeay::X509_NAME_print_ex($issuer_name, $flag_rfc22536_utf8, 1); |
196
|
0
|
|
|
|
|
|
for my $i (0..$issuer_count-1) { |
197
|
0
|
|
|
|
|
|
my $entry = Net::SSLeay::X509_NAME_get_entry($issuer_name, $i); |
198
|
0
|
|
|
|
|
|
my $asn1_string = Net::SSLeay::X509_NAME_ENTRY_get_data($entry); |
199
|
0
|
|
|
|
|
|
my $asn1_object = Net::SSLeay::X509_NAME_ENTRY_get_object($entry); |
200
|
0
|
|
|
|
|
|
my $nid = Net::SSLeay::OBJ_obj2nid($asn1_object); |
201
|
0
|
0
|
|
|
|
|
$rv->{issuer}->{entries}->[$i] = { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
202
|
|
|
|
|
|
|
oid => Net::SSLeay::OBJ_obj2txt($asn1_object,1), |
203
|
|
|
|
|
|
|
data => Net::SSLeay::P_ASN1_STRING_get($asn1_string), |
204
|
|
|
|
|
|
|
data_utf8_decoded => Net::SSLeay::P_ASN1_STRING_get($asn1_string, 1), |
205
|
|
|
|
|
|
|
nid => ($nid>0) ? $nid : undef, |
206
|
|
|
|
|
|
|
ln => ($nid>0) ? Net::SSLeay::OBJ_nid2ln($nid) : undef, |
207
|
|
|
|
|
|
|
sn => ($nid>0) ? Net::SSLeay::OBJ_nid2sn($nid) : undef, |
208
|
|
|
|
|
|
|
}; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
#warn "Info: dumping alternative names\n"; |
212
|
0
|
|
|
|
|
|
$rv->{subject}->{altnames} = [ Net::SSLeay::X509_get_subjectAltNames($x509) ]; |
213
|
|
|
|
|
|
|
#XXX-TODO maybe add a function for dumping issuerAltNames |
214
|
|
|
|
|
|
|
#$rv->{issuer}->{altnames} = [ Net::SSLeay::X509_get_issuerAltNames($x509) ]; |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
#warn "Info: dumping hashes/fingerprints\n"; |
217
|
0
|
|
|
|
|
|
$rv->{hash}->{subject} = { dec=>Net::SSLeay::X509_subject_name_hash($x509), hex=>sprintf("%X",Net::SSLeay::X509_subject_name_hash($x509)) }; |
218
|
0
|
|
|
|
|
|
$rv->{hash}->{issuer} = { dec=>Net::SSLeay::X509_issuer_name_hash($x509), hex=>sprintf("%X",Net::SSLeay::X509_issuer_name_hash($x509)) }; |
219
|
0
|
|
|
|
|
|
$rv->{hash}->{issuer_and_serial} = { dec=>Net::SSLeay::X509_issuer_and_serial_hash($x509), hex=>sprintf("%X",Net::SSLeay::X509_issuer_and_serial_hash($x509)) }; |
220
|
0
|
|
|
|
|
|
$rv->{fingerprint}->{md5} = Net::SSLeay::X509_get_fingerprint($x509, "md5"); |
221
|
0
|
|
|
|
|
|
$rv->{fingerprint}->{sha1} = Net::SSLeay::X509_get_fingerprint($x509, "sha1"); |
222
|
0
|
|
|
|
|
|
my $sha1_digest = Net::SSLeay::EVP_get_digestbyname("sha1"); |
223
|
0
|
|
|
|
|
|
$rv->{digest_sha1}->{pubkey} = Net::SSLeay::X509_pubkey_digest($x509, $sha1_digest); |
224
|
0
|
|
|
|
|
|
$rv->{digest_sha1}->{x509} = Net::SSLeay::X509_digest($x509, $sha1_digest); |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
#warn "Info: dumping expiration\n"; |
227
|
0
|
|
|
|
|
|
$rv->{not_before} = Net::SSLeay::P_ASN1_TIME_get_isotime(Net::SSLeay::X509_get_notBefore($x509)); |
228
|
0
|
|
|
|
|
|
$rv->{not_after} = Net::SSLeay::P_ASN1_TIME_get_isotime(Net::SSLeay::X509_get_notAfter($x509)); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
#warn "Info: dumping serial number\n"; |
231
|
0
|
|
|
|
|
|
my $ai = Net::SSLeay::X509_get_serialNumber($x509); |
232
|
|
|
|
|
|
|
$rv->{serial} = { |
233
|
0
|
|
|
|
|
|
hex => Net::SSLeay::P_ASN1_INTEGER_get_hex($ai), |
234
|
|
|
|
|
|
|
dec => Net::SSLeay::P_ASN1_INTEGER_get_dec($ai), |
235
|
|
|
|
|
|
|
long => Net::SSLeay::ASN1_INTEGER_get($ai), |
236
|
|
|
|
|
|
|
}; |
237
|
0
|
|
|
|
|
|
$rv->{version} = Net::SSLeay::X509_get_version($x509); |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
#warn "Info: dumping extensions\n"; |
240
|
0
|
|
|
|
|
|
my $ext_count = Net::SSLeay::X509_get_ext_count($x509); |
241
|
0
|
|
|
|
|
|
$rv->{extensions}->{count} = $ext_count; |
242
|
0
|
|
|
|
|
|
for my $i (0..$ext_count-1) { |
243
|
0
|
|
|
|
|
|
my $ext = Net::SSLeay::X509_get_ext($x509,$i); |
244
|
0
|
|
|
|
|
|
my $asn1_string = Net::SSLeay::X509_EXTENSION_get_data($ext); |
245
|
0
|
|
|
|
|
|
my $asn1_object = Net::SSLeay::X509_EXTENSION_get_object($ext); |
246
|
0
|
|
|
|
|
|
my $nid = Net::SSLeay::OBJ_obj2nid($asn1_object); |
247
|
0
|
0
|
|
|
|
|
$rv->{extensions}->{entries}->[$i] = { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
248
|
|
|
|
|
|
|
critical => Net::SSLeay::X509_EXTENSION_get_critical($ext), |
249
|
|
|
|
|
|
|
oid => Net::SSLeay::OBJ_obj2txt($asn1_object,1), |
250
|
|
|
|
|
|
|
nid => ($nid>0) ? $nid : undef, |
251
|
|
|
|
|
|
|
ln => ($nid>0) ? Net::SSLeay::OBJ_nid2ln($nid) : undef, |
252
|
|
|
|
|
|
|
sn => ($nid>0) ? Net::SSLeay::OBJ_nid2sn($nid) : undef, |
253
|
|
|
|
|
|
|
data => Net::SSLeay::X509V3_EXT_print($ext), |
254
|
|
|
|
|
|
|
}; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
#warn "Info: dumping CDP\n"; |
258
|
0
|
|
|
|
|
|
$rv->{cdp} = [ Net::SSLeay::P_X509_get_crl_distribution_points($x509) ]; |
259
|
|
|
|
|
|
|
#warn "Info: dumping extended key usage\n"; |
260
|
|
|
|
|
|
|
$rv->{extkeyusage} = { |
261
|
0
|
|
|
|
|
|
oid => [ Net::SSLeay::P_X509_get_ext_key_usage($x509,0) ], |
262
|
|
|
|
|
|
|
nid => [ Net::SSLeay::P_X509_get_ext_key_usage($x509,1) ], |
263
|
|
|
|
|
|
|
sn => [ Net::SSLeay::P_X509_get_ext_key_usage($x509,2) ], |
264
|
|
|
|
|
|
|
ln => [ Net::SSLeay::P_X509_get_ext_key_usage($x509,3) ], |
265
|
|
|
|
|
|
|
}; |
266
|
|
|
|
|
|
|
#warn "Info: dumping key usage\n"; |
267
|
0
|
|
|
|
|
|
$rv->{keyusage} = [ Net::SSLeay::P_X509_get_key_usage($x509) ]; |
268
|
|
|
|
|
|
|
#warn "Info: dumping netscape cert type\n"; |
269
|
0
|
|
|
|
|
|
$rv->{ns_cert_type} = [ Net::SSLeay::P_X509_get_netscape_cert_type($x509) ]; |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
#warn "Info: dumping other info\n"; |
272
|
0
|
|
|
|
|
|
$rv->{certificate_type} = Net::SSLeay::X509_certificate_type($x509); |
273
|
0
|
|
|
|
|
|
$rv->{signature_alg} = Net::SSLeay::OBJ_obj2txt(Net::SSLeay::P_X509_get_signature_alg($x509)); |
274
|
0
|
|
|
|
|
|
$rv->{pubkey_alg} = Net::SSLeay::OBJ_obj2txt(Net::SSLeay::P_X509_get_pubkey_alg($x509)); |
275
|
0
|
|
|
|
|
|
$rv->{pubkey_size} = Net::SSLeay::EVP_PKEY_size(Net::SSLeay::X509_get_pubkey($x509)); |
276
|
0
|
|
|
|
|
|
$rv->{pubkey_bits} = Net::SSLeay::EVP_PKEY_bits(Net::SSLeay::X509_get_pubkey($x509)); |
277
|
0
|
|
|
|
|
|
$rv->{pubkey_id} = Net::SSLeay::EVP_PKEY_id(Net::SSLeay::X509_get_pubkey($x509)); |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
return $rv; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# This routine will only check the certificate chain, not the actual contact |
283
|
|
|
|
|
|
|
# of the certificate. You still have to check for CN validity and expiration date. |
284
|
|
|
|
|
|
|
sub verify { |
285
|
0
|
|
|
0
|
0
|
|
my ($ok, $x509_store_ctx) = @_; |
286
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
print "**** Verify called ($ok)\n"; |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
|
my $x = Net::SSLeay::X509_STORE_CTX_get_current_cert($x509_store_ctx); |
290
|
0
|
0
|
|
|
|
|
if ($x) { |
291
|
0
|
|
|
|
|
|
print "Certificate:\n"; |
292
|
0
|
|
|
|
|
|
print " Subject Name: " |
293
|
|
|
|
|
|
|
. Net::SSLeay::X509_NAME_oneline( |
294
|
|
|
|
|
|
|
Net::SSLeay::X509_get_subject_name($x)) |
295
|
|
|
|
|
|
|
. "\n"; |
296
|
0
|
|
|
|
|
|
print " Issuer Name: " |
297
|
|
|
|
|
|
|
. Net::SSLeay::X509_NAME_oneline( |
298
|
|
|
|
|
|
|
Net::SSLeay::X509_get_issuer_name($x)) |
299
|
|
|
|
|
|
|
. "\n"; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
return $ok; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub getcertificate2 { |
306
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
307
|
0
|
|
|
|
|
|
my ($host, $port) = @_; |
308
|
|
|
|
|
|
|
|
309
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('getcertificate2', $host) or return; |
310
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('getcertificate2', $port) or return; |
311
|
|
|
|
|
|
|
|
312
|
0
|
|
|
|
|
|
eval("use Net::SSLeay qw(print_errs set_fd);"); |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
|
if (defined($ENV{HTTPS_PROXY})) { |
315
|
0
|
|
|
|
|
|
my $proxy = URI->new($ENV{HTTPS_PROXY}); |
316
|
0
|
|
|
|
|
|
my $user = ''; |
317
|
0
|
|
|
|
|
|
my $pass = ''; |
318
|
0
|
|
|
|
|
|
my $userinfo = $proxy->userinfo; |
319
|
0
|
0
|
|
|
|
|
if (defined($userinfo)) { |
320
|
0
|
|
|
|
|
|
($user, $pass) = split(':', $userinfo); |
321
|
|
|
|
|
|
|
} |
322
|
0
|
|
|
|
|
|
my $host = $proxy->host; |
323
|
0
|
|
|
|
|
|
my $port = $proxy->port; |
324
|
0
|
|
|
|
|
|
Net::SSLeay::set_proxy($host, $port, $user, $pass); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Taken from Net::SSLeay source code: sslcat() |
328
|
0
|
|
|
|
|
|
my ($got, $errs) = Net::SSLeay::open_proxy_tcp_connection($host, $port); |
329
|
0
|
0
|
|
|
|
|
if (! $got) { |
330
|
0
|
|
|
|
|
|
return $self->log->error("Net::SSLeay::open_proxy_tcp_connection: $errs"); |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
Net::SSLeay::initialize(); |
334
|
|
|
|
|
|
|
|
335
|
0
|
|
|
|
|
|
my $ctx = Net::SSLeay::new_x_ctx(); |
336
|
0
|
0
|
0
|
|
|
|
if ($errs = print_errs('Net::SSLeay::new_x_ctx') || ! $ctx) { |
337
|
0
|
|
|
|
|
|
return $self->log->error($errs); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL); |
341
|
0
|
0
|
|
|
|
|
if ($errs = print_errs('Net::SSLeay::CTX_set_options')) { |
342
|
0
|
|
|
|
|
|
return $self->log->error($errs); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# Certificate chain verification routines |
346
|
0
|
|
|
|
|
|
Net::SSLeay::CTX_set_default_verify_paths($ctx); |
347
|
0
|
|
|
|
|
|
my $cert_dir = '/etc/ssl/certs'; |
348
|
0
|
0
|
|
|
|
|
Net::SSLeay::CTX_load_verify_locations($ctx, '', $cert_dir) |
349
|
|
|
|
|
|
|
or return $self->log->error("CTX load verify loc=`$cert_dir' $!"); |
350
|
0
|
|
|
|
|
|
Net::SSLeay::CTX_set_verify($ctx, 0, \&verify); |
351
|
|
|
|
|
|
|
#die_if_ssl_error('callback: ctx set verify'); |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# XXX: skipped client certs part from sslcat() |
354
|
|
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
my $ssl = Net::SSLeay::new($ctx); |
356
|
0
|
0
|
|
|
|
|
if ($errs = print_errs('Net::SSLeay::new')) { |
357
|
0
|
|
|
|
|
|
return $self->log->error($errs); |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
0
|
|
|
|
|
|
set_fd($ssl, fileno(Net::SSLeay::SSLCAT_S())); |
361
|
0
|
0
|
|
|
|
|
if ($errs = print_errs('fileno')) { |
362
|
0
|
|
|
|
|
|
return $self->log->error($errs); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# Gather cipher list |
366
|
0
|
|
|
|
|
|
my $i = 0; |
367
|
0
|
|
|
|
|
|
my @cipher_list = (); |
368
|
0
|
|
|
|
|
|
my $cont = 1; |
369
|
0
|
|
|
|
|
|
while ($cont) { |
370
|
0
|
|
|
|
|
|
my $cipher = Net::SSLeay::get_cipher_list($ssl, $i); |
371
|
0
|
0
|
|
|
|
|
if (! $cipher) { |
372
|
|
|
|
|
|
|
#print "DEBUG last cipher\n"; |
373
|
0
|
|
|
|
|
|
$cont = 0; |
374
|
0
|
|
|
|
|
|
last; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
#print "cipher [$cipher]\n"; |
377
|
0
|
|
|
|
|
|
push @cipher_list, $cipher; |
378
|
0
|
|
|
|
|
|
$i++; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
$got = Net::SSLeay::connect($ssl); |
382
|
0
|
0
|
|
|
|
|
if (! $got) { |
383
|
0
|
|
|
|
|
|
$errs = print_errs('Net::SSLeay::connect'); |
384
|
0
|
|
|
|
|
|
return $self->log->error($errs); |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
|
my $cipher = Net::SSLeay::get_cipher($ssl); |
388
|
0
|
|
|
|
|
|
print "Using cipher [$cipher]\n"; |
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
print Net::SSLeay::dump_peer_certificate($ssl); |
391
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
my $server_cert = Net::SSLeay::get_peer_certificate($ssl); |
393
|
|
|
|
|
|
|
#print "get_peer_certificate: ".Data::Dumper::Dumper($server_cert)."\n"; |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
my $cert_details = get_cert_details($server_cert); |
396
|
|
|
|
|
|
|
#print Data::Dumper::Dumper($cert_details)."\n"; |
397
|
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
|
my @rv = Net::SSLeay::get_peer_cert_chain($ssl); |
399
|
|
|
|
|
|
|
#print "get_peer_cert_chain: ".Data::Dumper::Dumper(\@rv)."\n"; |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
my $rv = Net::SSLeay::get_verify_result($ssl); |
402
|
0
|
|
|
|
|
|
print "get_verify_result: ".Data::Dumper::Dumper($rv)."\n"; |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
#print 'Subject Name: '.Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($server_cert)). |
405
|
|
|
|
|
|
|
#"\n".'Issuer Name: '.Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_issuer_name($server_cert))."\n"; |
406
|
|
|
|
|
|
|
|
407
|
0
|
|
|
|
|
|
my $subj_name = Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($server_cert)); |
408
|
0
|
|
|
|
|
|
print "$subj_name\n"; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
#my $pem = Net::SSLeay::PEM_get_string_X509_CRL($server_cert); |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# |
415
|
|
|
|
|
|
|
# X509 certificate details |
416
|
|
|
|
|
|
|
# |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# # X509 version |
419
|
|
|
|
|
|
|
# my $version = Net::SSLeay::X509_get_version($server_cert); |
420
|
|
|
|
|
|
|
# print "version: $version\n"; |
421
|
|
|
|
|
|
|
# |
422
|
|
|
|
|
|
|
# # Number of extension used |
423
|
|
|
|
|
|
|
# my $ext_count = Net::SSLeay::X509_get_ext_count($server_cert); |
424
|
|
|
|
|
|
|
# print "ext_count: $ext_count\n"; |
425
|
|
|
|
|
|
|
# |
426
|
|
|
|
|
|
|
# # Extensions |
427
|
|
|
|
|
|
|
# # X509_get_ext |
428
|
|
|
|
|
|
|
# for my $index (0..$ext_count-1) { |
429
|
|
|
|
|
|
|
# my $ext = Net::SSLeay::X509_get_ext($server_cert, $index); |
430
|
|
|
|
|
|
|
# #my $data = Net::SSLeay::X509_EXTENSION_get_data($ext); |
431
|
|
|
|
|
|
|
# #my $string = Net::SSLeay::P_ASN1_STRING_get($data); |
432
|
|
|
|
|
|
|
# #print Data::Dumper::Dumper($string)."\n"; |
433
|
|
|
|
|
|
|
# |
434
|
|
|
|
|
|
|
# print "EXT: ".Net::SSLeay::X509V3_EXT_print($ext)."\n"; |
435
|
|
|
|
|
|
|
# } |
436
|
|
|
|
|
|
|
# |
437
|
|
|
|
|
|
|
# # Fingerprint |
438
|
|
|
|
|
|
|
# my $fingerprint = Net::SSLeay::X509_get_fingerprint($server_cert, "md5"); |
439
|
|
|
|
|
|
|
# print "MD5 fingerprint: $fingerprint\n"; |
440
|
|
|
|
|
|
|
# $fingerprint = Net::SSLeay::X509_get_fingerprint($server_cert, "sha1"); |
441
|
|
|
|
|
|
|
# print "SHA-1 fingerprint: $fingerprint\n"; |
442
|
|
|
|
|
|
|
# $fingerprint = Net::SSLeay::X509_get_fingerprint($server_cert, "sha256"); |
443
|
|
|
|
|
|
|
# print "SHA-256 fingerprint: $fingerprint\n"; |
444
|
|
|
|
|
|
|
# $fingerprint = Net::SSLeay::X509_get_fingerprint($server_cert, "ripemd160"); |
445
|
|
|
|
|
|
|
# print "RIPEMD160 fingerprint: $fingerprint\n"; |
446
|
|
|
|
|
|
|
# |
447
|
|
|
|
|
|
|
# # Issuer name |
448
|
|
|
|
|
|
|
# my $issuer = Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_issuer_name($server_cert)); |
449
|
|
|
|
|
|
|
# print "issuer: $issuer\n"; |
450
|
|
|
|
|
|
|
# |
451
|
|
|
|
|
|
|
# # Not after |
452
|
|
|
|
|
|
|
# my $time = Net::SSLeay::X509_get_notAfter($server_cert); |
453
|
|
|
|
|
|
|
# my $not_after = Net::SSLeay::P_ASN1_TIME_get_isotime($time); |
454
|
|
|
|
|
|
|
# print "not after: $not_after\n"; |
455
|
|
|
|
|
|
|
# |
456
|
|
|
|
|
|
|
# # Not before |
457
|
|
|
|
|
|
|
# $time = Net::SSLeay::X509_get_notBefore($server_cert); |
458
|
|
|
|
|
|
|
# my $not_before = Net::SSLeay::P_ASN1_TIME_get_isotime($time); |
459
|
|
|
|
|
|
|
# print "not before: $not_before\n"; |
460
|
|
|
|
|
|
|
# |
461
|
|
|
|
|
|
|
# # What kind of encryption is using the public key |
462
|
|
|
|
|
|
|
# my $pubkey = Net::SSLeay::X509_get_pubkey($server_cert); |
463
|
|
|
|
|
|
|
# my $type = Net::SSLeay::EVP_PKEY_id($pubkey); |
464
|
|
|
|
|
|
|
# my $encryption_type = Net::SSLeay::OBJ_nid2sn($type); |
465
|
|
|
|
|
|
|
# print "pubkey: $encryption_type\n"; |
466
|
|
|
|
|
|
|
# |
467
|
|
|
|
|
|
|
# # |
468
|
|
|
|
|
|
|
# @rv = Net::SSLeay::X509_get_subjectAltNames($server_cert); |
469
|
|
|
|
|
|
|
# print Data::Dumper::Dumper(\@rv)."\n"; |
470
|
|
|
|
|
|
|
# |
471
|
|
|
|
|
|
|
# # Serial number |
472
|
|
|
|
|
|
|
# my $serial_number = Net::SSLeay::X509_get_serialNumber($server_cert); |
473
|
|
|
|
|
|
|
# print "serial_number: $serial_number\n"; |
474
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
return $server_cert; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
1; |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
__END__ |