| 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
|
|
873
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
29
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
26
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
5
|
use base qw(Metabrik); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2755
|
|
|
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
|
|
709
|
eval("use Net::SSLeay qw/XN_FLAG_RFC2253 ASN1_STRFLGS_ESC_MSB/;"); |
|
|
1
|
|
|
|
|
11857
|
|
|
|
1
|
|
|
|
|
461
|
|
|
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__ |