| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
1
|
|
|
1
|
|
1077
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
31
|
|
|
2
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
39
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Net::IMP::Example::LogServerCertificate; |
|
5
|
1
|
|
|
1
|
|
6
|
use base 'Net::IMP::Base'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
118
|
|
|
6
|
1
|
|
|
1
|
|
6
|
use Net::SSLeay; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
42
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
use fields ( |
|
9
|
1
|
|
|
|
|
5
|
'done', # done or no SSL |
|
10
|
|
|
|
|
|
|
'sbuf', # buffer on server side |
|
11
|
1
|
|
|
1
|
|
5
|
); |
|
|
1
|
|
|
|
|
1
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
84
|
use Net::IMP qw(:log :DEFAULT); # import IMP_ constants |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
183
|
|
|
14
|
1
|
|
|
1
|
|
7
|
use Net::IMP::Debug; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
5
|
|
|
15
|
1
|
|
|
1
|
|
7
|
use Carp 'croak'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
966
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub INTERFACE { |
|
18
|
|
|
|
|
|
|
return ([ |
|
19
|
|
|
|
|
|
|
undef, |
|
20
|
0
|
|
|
0
|
0
|
|
[ IMP_PASS, IMP_PREPASS, IMP_LOG ] |
|
21
|
|
|
|
|
|
|
]) |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# create new analyzer object |
|
26
|
|
|
|
|
|
|
sub new_analyzer { |
|
27
|
0
|
|
|
0
|
1
|
|
my ($factory,%args) = @_; |
|
28
|
0
|
|
|
|
|
|
my $self = $factory->SUPER::new_analyzer(%args); |
|
29
|
|
|
|
|
|
|
|
|
30
|
0
|
|
|
|
|
|
$self->run_callback( |
|
31
|
|
|
|
|
|
|
# we are not interested in data from client |
|
32
|
|
|
|
|
|
|
[ IMP_PASS, 0, IMP_MAXOFFSET ], |
|
33
|
|
|
|
|
|
|
# and we will not change data from server, only inspect |
|
34
|
|
|
|
|
|
|
[ IMP_PREPASS, 1, IMP_MAXOFFSET ], |
|
35
|
|
|
|
|
|
|
); |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
$self->{sbuf} = ''; |
|
38
|
0
|
|
|
|
|
|
return $self; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub data { |
|
42
|
0
|
|
|
0
|
1
|
|
my ($self,$dir,$data) = @_; |
|
43
|
0
|
0
|
|
|
|
|
return if $dir == 0; # should not happen |
|
44
|
0
|
0
|
|
|
|
|
return if $self->{done}; # done or no SSL |
|
45
|
0
|
0
|
|
|
|
|
return if $data eq ''; # eof from server |
|
46
|
|
|
|
|
|
|
|
|
47
|
0
|
|
|
|
|
|
my $buf = $self->{sbuf} .= $data; |
|
48
|
|
|
|
|
|
|
|
|
49
|
0
|
0
|
0
|
|
|
|
if ( _read_ssl_handshake($self,\$buf,2) # Server Hello |
|
50
|
|
|
|
|
|
|
and my $certs = _read_ssl_handshake($self,\$buf,11) # Certificates |
|
51
|
|
|
|
|
|
|
) { |
|
52
|
0
|
|
|
|
|
|
$self->{done} = 1; |
|
53
|
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
my ($len) = unpack("xa3",substr($certs,0,4,'')); |
|
55
|
0
|
|
|
|
|
|
$len = unpack("N","\0$len"); |
|
56
|
0
|
|
|
|
|
|
substr($certs,$len) = ''; |
|
57
|
0
|
|
|
|
|
|
$len = unpack("N","\0".substr($certs,0,3,'')); |
|
58
|
0
|
|
|
|
|
|
substr($certs,$len) = ''; |
|
59
|
0
|
|
|
|
|
|
my $i = 0; |
|
60
|
0
|
|
|
|
|
|
while ($certs ne '') { |
|
61
|
0
|
|
|
|
|
|
my $clen = unpack("N","\0".substr($certs,0,3,'')); |
|
62
|
0
|
|
|
|
|
|
my $cert = substr($certs,0,$clen,''); |
|
63
|
0
|
0
|
|
|
|
|
length($cert) == $clen or |
|
64
|
|
|
|
|
|
|
die "invalid certificate length ($clen vs. ".length($cert).")"; |
|
65
|
0
|
0
|
|
|
|
|
if ( my $line = eval { _cert2line($cert) } ) { |
|
|
0
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
$self->run_callback([ IMP_LOG,1,0,0,IMP_LOG_INFO, |
|
67
|
|
|
|
|
|
|
sprintf("chain[%d]: %s",$i,$line)]); |
|
68
|
|
|
|
|
|
|
} else { |
|
69
|
0
|
|
|
|
|
|
warn "failed to convert cert to string: $@"; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
0
|
|
|
|
|
|
$i++; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
$self->run_callback([ IMP_PASS,1,IMP_MAXOFFSET ]) |
|
76
|
0
|
0
|
|
|
|
|
if $self->{done}; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub _cert2line { |
|
80
|
0
|
|
|
0
|
|
|
my $der = shift; |
|
81
|
0
|
|
|
|
|
|
my $bio = Net::SSLeay::BIO_new( Net::SSLeay::BIO_s_mem()); |
|
82
|
0
|
|
|
|
|
|
Net::SSLeay::BIO_write($bio,$der); |
|
83
|
0
|
|
|
|
|
|
my $cert = Net::SSLeay::d2i_X509_bio($bio); |
|
84
|
0
|
|
|
|
|
|
Net::SSLeay::BIO_free($bio); |
|
85
|
0
|
0
|
|
|
|
|
$cert or die "cannot parse certificate: ". |
|
86
|
|
|
|
|
|
|
Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()); |
|
87
|
0
|
|
|
|
|
|
my $not_before = Net::SSLeay::X509_get_notBefore($cert); |
|
88
|
0
|
|
|
|
|
|
my $not_after = Net::SSLeay::X509_get_notAfter($cert); |
|
89
|
0
|
|
|
|
|
|
$_ = Net::SSLeay::P_ASN1_TIME_put2string($_) for($not_before,$not_after); |
|
90
|
0
|
|
|
|
|
|
my $subject = Net::SSLeay::X509_NAME_oneline( |
|
91
|
|
|
|
|
|
|
Net::SSLeay::X509_get_subject_name($cert)); |
|
92
|
0
|
|
|
|
|
|
return "$subject | $not_before - $not_after"; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _read_ssl_handshake { |
|
97
|
0
|
|
|
0
|
|
|
my ($self,$buf,$expect_htype) = @_; |
|
98
|
0
|
0
|
|
|
|
|
return if length($$buf) < 22; # need way more data |
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
my ($ctype,$version,$len,$htype) = unpack('CnnC',$$buf); |
|
101
|
0
|
0
|
|
|
|
|
if ($ctype != 22) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
debug("no SSL >=3.0 handshake record"); |
|
103
|
0
|
|
|
|
|
|
goto bad; |
|
104
|
|
|
|
|
|
|
} elsif ( $len > 2**14 ) { |
|
105
|
0
|
|
|
|
|
|
debug("length looks way too big - assuming no ssl"); |
|
106
|
0
|
|
|
|
|
|
goto bad; |
|
107
|
|
|
|
|
|
|
} elsif ( $htype != $expect_htype ) { |
|
108
|
0
|
|
|
|
|
|
debug("unexpected handshake type $htype - assuming no ssl"); |
|
109
|
0
|
|
|
|
|
|
goto bad; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
0
|
0
|
|
|
|
|
length($$buf)-5 >= $len or return; # need more data |
|
113
|
0
|
|
|
|
|
|
substr($$buf,0,5,''); |
|
114
|
0
|
|
|
|
|
|
debug("got handshake type $htype length $len"); |
|
115
|
0
|
|
|
|
|
|
return substr($$buf,0,$len,''); |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
bad: |
|
118
|
0
|
|
|
|
|
|
$self->{done} = 1; |
|
119
|
0
|
|
|
|
|
|
return; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# debugging stuff |
|
124
|
|
|
|
|
|
|
sub _hexdump { |
|
125
|
0
|
|
|
0
|
|
|
my ($buf,$len) = @_; |
|
126
|
0
|
0
|
|
|
|
|
$buf = substr($buf,0,$len) if $len; |
|
127
|
0
|
|
|
|
|
|
my @hx = map { sprintf("%02x",$_) } unpack('C*',$buf); |
|
|
0
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
my $t = ''; |
|
129
|
0
|
|
|
|
|
|
while (@hx) { |
|
130
|
0
|
|
|
|
|
|
$t .= join(' ',splice(@hx,0,16))."\n"; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
0
|
|
|
|
|
|
return $t; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
1; |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
__END__ |