line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package IO::Socket::SSL::Intercept; |
3
|
1
|
|
|
1
|
|
624
|
use strict; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
35
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
5
|
1
|
|
|
1
|
|
5
|
use Carp 'croak'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
58
|
|
6
|
1
|
|
|
1
|
|
526
|
use IO::Socket::SSL::Utils; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
174
|
|
7
|
1
|
|
|
1
|
|
8
|
use Net::SSLeay; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1284
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '2.056'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub new { |
13
|
0
|
|
|
0
|
1
|
|
my ($class,%args) = @_; |
14
|
|
|
|
|
|
|
|
15
|
0
|
|
|
|
|
|
my $cacert = delete $args{proxy_cert}; |
16
|
0
|
0
|
|
|
|
|
if ( ! $cacert ) { |
17
|
0
|
0
|
|
|
|
|
if ( my $f = delete $args{proxy_cert_file} ) { |
18
|
0
|
|
|
|
|
|
$cacert = PEM_file2cert($f); |
19
|
|
|
|
|
|
|
} else { |
20
|
0
|
|
|
|
|
|
croak "no proxy_cert or proxy_cert_file given"; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
} |
23
|
|
|
|
|
|
|
|
24
|
0
|
|
|
|
|
|
my $cakey = delete $args{proxy_key}; |
25
|
0
|
0
|
|
|
|
|
if ( ! $cakey ) { |
26
|
0
|
0
|
|
|
|
|
if ( my $f = delete $args{proxy_key_file} ) { |
27
|
0
|
|
|
|
|
|
$cakey = PEM_file2key($f); |
28
|
|
|
|
|
|
|
} else { |
29
|
0
|
|
|
|
|
|
croak "no proxy_cert or proxy_cert_file given"; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
0
|
|
|
|
|
|
my $certkey = delete $args{cert_key}; |
34
|
0
|
0
|
|
|
|
|
if ( ! $certkey ) { |
35
|
0
|
0
|
|
|
|
|
if ( my $f = delete $args{cert_key_file} ) { |
36
|
0
|
|
|
|
|
|
$certkey = PEM_file2key($f); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
0
|
|
0
|
|
|
|
my $cache = delete $args{cache} || {}; |
41
|
0
|
0
|
|
|
|
|
if (ref($cache) eq 'CODE') { |
42
|
|
|
|
|
|
|
# check cache type |
43
|
0
|
|
|
|
|
|
my $type = $cache->('type'); |
44
|
0
|
0
|
|
|
|
|
if (!$type) { |
|
|
0
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# old cache interface - change into new interface |
46
|
|
|
|
|
|
|
# get: $cache->(fp) |
47
|
|
|
|
|
|
|
# set: $cache->(fp,cert,key) |
48
|
0
|
|
|
|
|
|
my $oc = $cache; |
49
|
|
|
|
|
|
|
$cache = sub { |
50
|
0
|
|
|
0
|
|
|
my ($fp,$create_cb) = @_; |
51
|
0
|
|
|
|
|
|
my @ck = $oc->($fp); |
52
|
0
|
0
|
|
|
|
|
$oc->($fp, @ck = &$create_cb) if !@ck; |
53
|
0
|
|
|
|
|
|
return @ck; |
54
|
0
|
|
|
|
|
|
}; |
55
|
|
|
|
|
|
|
} elsif ($type == 1) { |
56
|
|
|
|
|
|
|
# current interface: |
57
|
|
|
|
|
|
|
# get/set: $cache->(fp,cb_create) |
58
|
|
|
|
|
|
|
} else { |
59
|
0
|
|
|
|
|
|
die "invalid type of cache: $type"; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
my $self = bless { |
64
|
|
|
|
|
|
|
cacert => $cacert, |
65
|
|
|
|
|
|
|
cakey => $cakey, |
66
|
|
|
|
|
|
|
certkey => $certkey, |
67
|
|
|
|
|
|
|
cache => $cache, |
68
|
|
|
|
|
|
|
serial => delete $args{serial}, |
69
|
0
|
|
|
|
|
|
}; |
70
|
0
|
|
|
|
|
|
return $self; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub DESTROY { |
74
|
|
|
|
|
|
|
# call various ssl _free routines |
75
|
0
|
0
|
|
0
|
|
|
my $self = shift or return; |
76
|
0
|
0
|
|
|
|
|
for ( \$self->{cacert}, |
77
|
0
|
|
|
|
|
|
map { \$_->{cert} } ref($self->{cache}) ne 'CODE' ? values %{$self->{cache}} :()) { |
|
0
|
|
|
|
|
|
|
78
|
0
|
0
|
|
|
|
|
$$_ or next; |
79
|
0
|
|
|
|
|
|
CERT_free($$_); |
80
|
0
|
|
|
|
|
|
$$_ = undef; |
81
|
|
|
|
|
|
|
} |
82
|
0
|
|
|
|
|
|
for ( \$self->{cakey}, \$self->{pubkey} ) { |
83
|
0
|
0
|
|
|
|
|
$$_ or next; |
84
|
0
|
|
|
|
|
|
KEY_free($$_); |
85
|
0
|
|
|
|
|
|
$$_ = undef; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub clone_cert { |
90
|
0
|
|
|
0
|
1
|
|
my ($self,$old_cert,$clone_key) = @_; |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
my $hash = CERT_asHash($old_cert); |
93
|
|
|
|
|
|
|
my $create_cb = sub { |
94
|
|
|
|
|
|
|
# if not in cache create new certificate based on original |
95
|
|
|
|
|
|
|
# copy most but not all extensions |
96
|
0
|
0
|
|
0
|
|
|
if (my $ext = $hash->{ext}) { |
97
|
|
|
|
|
|
|
@$ext = grep { |
98
|
0
|
0
|
|
|
|
|
defined($_->{sn}) && $_->{sn} !~m{^(?: |
|
0
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
authorityInfoAccess | |
100
|
|
|
|
|
|
|
subjectKeyIdentifier | |
101
|
|
|
|
|
|
|
authorityKeyIdentifier | |
102
|
|
|
|
|
|
|
certificatePolicies | |
103
|
|
|
|
|
|
|
crlDistributionPoints |
104
|
|
|
|
|
|
|
)$}x |
105
|
|
|
|
|
|
|
} @$ext; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
my ($clone,$key) = CERT_create( |
108
|
|
|
|
|
|
|
%$hash, |
109
|
|
|
|
|
|
|
issuer_cert => $self->{cacert}, |
110
|
|
|
|
|
|
|
issuer_key => $self->{cakey}, |
111
|
|
|
|
|
|
|
key => $self->{certkey}, |
112
|
|
|
|
|
|
|
serial => |
113
|
|
|
|
|
|
|
! defined($self->{serial}) ? (unpack('L',$hash->{x509_digest_sha256}))[0] : |
114
|
|
|
|
|
|
|
ref($self->{serial}) eq 'CODE' ? $self->{serial}($old_cert,$hash) : |
115
|
|
|
|
|
|
|
++$self->{serial}, |
116
|
0
|
0
|
|
|
|
|
); |
|
|
0
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
return ($clone,$key); |
118
|
0
|
|
|
|
|
|
}; |
119
|
|
|
|
|
|
|
|
120
|
0
|
|
0
|
|
|
|
$clone_key ||= substr(unpack("H*", $hash->{x509_digest_sha256}),0,32); |
121
|
0
|
|
|
|
|
|
my $c = $self->{cache}; |
122
|
0
|
0
|
|
|
|
|
return $c->($clone_key,$create_cb) if ref($c) eq 'CODE'; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
0
|
|
|
|
my $e = $c->{$clone_key} ||= do { |
125
|
0
|
|
|
|
|
|
my ($cert,$key) = &$create_cb; |
126
|
0
|
|
|
|
|
|
{ cert => $cert, key => $key }; |
127
|
|
|
|
|
|
|
}; |
128
|
0
|
|
|
|
|
|
$e->{atime} = time(); |
129
|
0
|
|
|
|
|
|
return ($e->{cert},$e->{key}); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
0
|
0
|
|
sub STORABLE_freeze { my $self = shift; $self->serialize() } |
|
0
|
|
|
|
|
|
|
134
|
0
|
|
|
0
|
0
|
|
sub STORABLE_thaw { my ($class,undef,$data) = @_; $class->unserialize($data) } |
|
0
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub serialize { |
137
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
138
|
0
|
|
|
|
|
|
my $data = pack("N",2); # version |
139
|
0
|
|
|
|
|
|
$data .= pack("N/a", PEM_cert2string($self->{cacert})); |
140
|
0
|
|
|
|
|
|
$data .= pack("N/a", PEM_key2string($self->{cakey})); |
141
|
0
|
0
|
|
|
|
|
if ( $self->{certkey} ) { |
142
|
0
|
|
|
|
|
|
$data .= pack("N/a", PEM_key2string($self->{certkey})); |
143
|
|
|
|
|
|
|
} else { |
144
|
0
|
|
|
|
|
|
$data .= pack("N/a", ''); |
145
|
|
|
|
|
|
|
} |
146
|
0
|
|
|
|
|
|
$data .= pack("N",$self->{serial}); |
147
|
0
|
0
|
|
|
|
|
if ( ref($self->{cache}) eq 'HASH' ) { |
148
|
0
|
|
|
|
|
|
while ( my($k,$v) = each %{ $self->{cache}} ) { |
|
0
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
$data .= pack("N/aN/aN/aN", $k, |
150
|
|
|
|
|
|
|
PEM_cert2string($k->{cert}), |
151
|
|
|
|
|
|
|
$k->{key} ? PEM_key2string($k->{key}) : '', |
152
|
0
|
0
|
|
|
|
|
$k->{atime}); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
0
|
|
|
|
|
|
return $data; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub unserialize { |
159
|
0
|
|
|
0
|
1
|
|
my ($class,$data) = @_; |
160
|
0
|
0
|
|
|
|
|
unpack("N",substr($data,0,4,'')) == 2 or |
161
|
|
|
|
|
|
|
croak("serialized with wrong version"); |
162
|
0
|
|
|
|
|
|
( my $cacert,my $cakey,my $certkey,my $serial,$data) |
163
|
|
|
|
|
|
|
= unpack("N/aN/aN/aNa*",$data); |
164
|
0
|
0
|
0
|
|
|
|
my $self = bless { |
165
|
|
|
|
|
|
|
serial => $serial, |
166
|
|
|
|
|
|
|
cacert => PEM_string2cert($cacert), |
167
|
|
|
|
|
|
|
cakey => PEM_string2key($cakey), |
168
|
|
|
|
|
|
|
$certkey ? ( certkey => PEM_string2key($certkey)):(), |
169
|
|
|
|
|
|
|
}, ref($class)||$class; |
170
|
|
|
|
|
|
|
|
171
|
0
|
0
|
|
|
|
|
$self->{cache} = {} if $data ne ''; |
172
|
0
|
|
|
|
|
|
while ( $data ne '' ) { |
173
|
0
|
|
|
|
|
|
(my $key,my $cert,my $certkey, my $atime,$data) = unpack("N/aN/aNa*",$data); |
174
|
0
|
0
|
|
|
|
|
$self->{cache}{$key} = { |
175
|
|
|
|
|
|
|
cert => PEM_string2cert($cert), |
176
|
|
|
|
|
|
|
$key ? ( key => PEM_string2key($certkey)):(), |
177
|
|
|
|
|
|
|
atime => $atime |
178
|
|
|
|
|
|
|
}; |
179
|
|
|
|
|
|
|
} |
180
|
0
|
|
|
|
|
|
return $self; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
1; |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
__END__ |