File Coverage

blib/lib/LWP/Protocol/https.pm
Criterion Covered Total %
statement 51 62 82.2
branch 13 32 40.6
condition 5 20 25.0
subroutine 8 8 100.0
pod 0 1 0.0
total 77 123 62.6


line stmt bran cond sub pod time code
1             package LWP::Protocol::https;
2              
3 3     3   1430074 use strict;
  3         9  
  3         128  
4 3     3   20 use warnings;
  3         12  
  3         260  
5              
6             our $VERSION = '6.15';
7              
8 3     3   22 use parent qw(LWP::Protocol::http);
  3         6  
  3         25  
9             require Net::HTTPS;
10              
11             sub socket_type
12             {
13 12     12 0 1595213 return "https";
14             }
15              
16             sub _extra_sock_opts
17             {
18 10     10   26038 my $self = shift;
19 10 50       30 my %ssl_opts = %{$self->{ua}{ssl_opts} || {}};
  10         121  
20 10 100       55 if (delete $ssl_opts{verify_hostname}) {
21 6   50     64 $ssl_opts{SSL_verify_mode} ||= 1;
22 6         38 $ssl_opts{SSL_verifycn_scheme} = 'www';
23             }
24             else {
25 4 50       25 if ( $Net::HTTPS::SSL_SOCKET_CLASS eq 'Net::SSL' ) {
26 0         0 $ssl_opts{SSL_verifycn_scheme} = '';
27             } else {
28 4         57 $ssl_opts{SSL_verifycn_scheme} = 'none';
29             }
30             }
31 10 100       40 if ($ssl_opts{SSL_verify_mode}) {
32 6 0 33     30 unless (exists $ssl_opts{SSL_ca_file} || exists $ssl_opts{SSL_ca_path}) {
33 0 0 0     0 if ($Net::HTTPS::SSL_SOCKET_CLASS eq 'IO::Socket::SSL'
    0 0        
34             && defined &IO::Socket::SSL::default_ca
35             && IO::Socket::SSL::default_ca() ) {
36             # IO::Socket::SSL has a usable default CA
37             } elsif ( my $cafile = eval {
38 0         0 require Mozilla::CA;
39 0         0 Mozilla::CA::SSL_ca_file()
40             }) {
41             # use Mozilla::CA
42 0         0 $ssl_opts{SSL_ca_file} = $cafile;
43             } else {
44 0         0 die <<'EOT';
45             Can't verify SSL peers without knowing which Certificate Authorities to trust.
46              
47             This problem can be fixed by either setting the PERL_LWP_SSL_CA_FILE
48             environment variable to the file where your trusted CA are, or by installing
49             the Mozilla::CA module for set of commonly trusted CAs.
50              
51             To completely disable the verification that you talk to the correct SSL peer you
52             can set SSL_verify_mode to 0 within ssl_opts. But, if you do this you can't be
53             sure that you communicate with the expected peer.
54             EOT
55             }
56             }
57             }
58 10         47 $self->{ssl_opts} = \%ssl_opts;
59 10         69 return (%ssl_opts, MultiHomed => 1, $self->SUPER::_extra_sock_opts);
60             }
61              
62             # This is a subclass of LWP::Protocol::http.
63             # That parent class calls ->_check_sock() during the
64             # request method. This allows us to hook in and run checks
65             # sub _check_sock
66             # {
67             # my($self, $req, $sock) = @_;
68             # }
69              
70             sub _get_sock_info
71             {
72 8     8   1369593 my $self = shift;
73 8         78 $self->SUPER::_get_sock_info(@_);
74 8         1734 my($res, $sock) = @_;
75 8 50 33     164 if ($sock->can('get_sslversion') and my $sslversion = $sock->get_sslversion) {
76 8         260 $res->header("Client-SSL-Version" => $sslversion);
77             }
78 8         692 $res->header("Client-SSL-Cipher" => $sock->get_cipher);
79 8         753 my $cert = $sock->get_peer_certificate;
80 8 50       50 if ($cert) {
81 8         33 $res->header("Client-SSL-Cert-Subject" => $cert->subject_name);
82 8         1024 $res->header("Client-SSL-Cert-Issuer" => $cert->issuer_name);
83             }
84 8 50       950 if (!$self->{ssl_opts}{SSL_verify_mode}) {
    0          
85 8         30 $res->push_header("Client-SSL-Warning" => "Peer certificate not verified");
86             }
87             elsif (!$self->{ssl_opts}{SSL_verifycn_scheme}) {
88 0         0 $res->push_header("Client-SSL-Warning" => "Peer hostname match with certificate not verified");
89             }
90 8         384 $res->header("Client-SSL-Socket-Class" => $Net::HTTPS::SSL_SOCKET_CLASS);
91             }
92              
93             # upgrade plain socket to SSL, used for CONNECT tunnel when proxying https
94             # will only work if the underlying socket class of Net::HTTPS is
95             # IO::Socket::SSL, but code will only be called in this case
96             if ( $Net::HTTPS::SSL_SOCKET_CLASS->can('start_SSL')) {
97             *_upgrade_sock = sub {
98 6     6   381194 my ($self,$sock,$url) = @_;
99             # SNI should be passed there only if it is not an IP address.
100             # Details: https://github.com/libwww-perl/libwww-perl/issues/449#issuecomment-1896175509
101 6 50       44 my $host = $url->host() =~ m/:|^[\d.]+$/s ? undef : $url->host();
102 6         395 my $usebio = {};
103 6 50 33     72 if (UNIVERSAL::can($sock,'is_SSL') && $sock->is_SSL) {
104 0 0       0 $usebio = eval { $Net::HTTPS::SSL_SOCKET_CLASS->can_nested_ssl } or
  0         0  
105             die "no support for nested TLS in this IO::Socket::SSL version";
106             }
107              
108 6         19 $sock = LWP::Protocol::https::Socket->start_SSL( my $osock = $sock,
109             SSL_verifycn_name => $url->host,
110             SSL_hostname => $host,
111             %$usebio,
112             $self->_extra_sock_opts,
113             );
114 6 50       642583 if (!$sock) {
115 0         0 $@ = LWP::Protocol::https::Socket->errstr;
116 0         0 return;
117             }
118 6 50 33     61 if ($usebio and my @fields = grep { /^http_/ } keys %{*$osock}) {
  200         421  
  6         160  
119             # propagate any http_ fields from osock to sock
120 6         15 @{*$sock}{@fields} = @{*$osock}{@fields}
  6         27  
  6         24  
121             }
122 6         57 return $sock;
123             }
124             }
125              
126             #-----------------------------------------------------------
127             package LWP::Protocol::https::Socket;
128              
129 3     3   134503 use parent -norequire, qw(Net::HTTPS LWP::Protocol::http::SocketMethods);
  3         15  
  3         30  
130              
131             1;
132              
133             __END__