commit 62dd58188d8f8987d24bd84951813a54a8bf5987 Author: Gisle Aas Date: Mon Jan 24 23:19:59 2011 +0100 Default to verifying hostnames when using SSL --- a/lib/LWP/Protocol/https.pm +++ b/lib/LWP/Protocol/https.pm @@ -11,18 +11,30 @@ sub socket_type return "https"; } -sub _check_sock +sub _extra_sock_opts { - my($self, $req, $sock) = @_; - if ($sock->can("verify_hostname")) { - if (!$sock->verify_hostname($req->uri->host, "www")) { - my $subject = $sock->peer_certificate("subject"); - die "SSL-peer fails verification [subject=$subject]\n"; - } - else { - $req->{ssl_sock_verified}++; + my $self = shift; + my %ssl_opts = %{$self->{ua}{ssl_opts} || {}}; + unless (exists $ssl_opts{SSL_verify_mode}) { + $ssl_opts{SSL_verify_mode} = 1; + } + if (delete $ssl_opts{verify_hostname}) { + $ssl_opts{SSL_verify_mode} ||= 1; + $ssl_opts{SSL_verifycn_scheme} = 'www'; + } + if ($ssl_opts{SSL_verify_mode}) { + unless (exists $ssl_opts{SSL_ca_file} || exists $ssl_opts{SSL_ca_path}) { + require Mozilla::CA; + $ssl_opts{SSL_ca_file} = Mozilla::CA::SSL_ca_file(); } } + $self->{ssl_opts} = \%ssl_opts; + return (%ssl_opts, $self->SUPER::_extra_sock_opts); +} + +sub _check_sock +{ + my($self, $req, $sock) = @_; my $check = $req->header("If-SSL-Cert-Subject"); if (defined $check) { my $cert = $sock->get_peer_certificate || @@ -45,12 +57,11 @@ sub _get_sock_info $res->header("Client-SSL-Cert-Subject" => $cert->subject_name); $res->header("Client-SSL-Cert-Issuer" => $cert->issuer_name); } - if (!$res->request->{ssl_sock_verified}) { - if(! eval { $sock->get_peer_verify }) { - my $msg = "Peer certificate not verified"; - $msg .= " [$@]" if $@; - $res->header("Client-SSL-Warning" => $msg); - } + if (!$self->{ssl_opts}{SSL_verify_mode}) { + $res->push_header("Client-SSL-Warning" => "Peer certificate not verified"); + } + elsif (!$self->{ssl_opts}{SSL_verifycn_scheme}) { + $res->push_header("Client-SSL-Warning" => "Peer hostname match with certificate not verified"); } $res->header("Client-SSL-Socket-Class" => $Net::HTTPS::SSL_SOCKET_CLASS); } --- a/lib/LWP/UserAgent.pm +++ b/lib/LWP/UserAgent.pm @@ -41,6 +41,7 @@ sub new my $timeout = delete $cnf{timeout}; $timeout = 3*60 unless defined $timeout; my $local_address = delete $cnf{local_address}; + my $ssl_opts = delete $cnf{ssl_opts}; my $use_eval = delete $cnf{use_eval}; $use_eval = 1 unless defined $use_eval; my $parse_head = delete $cnf{parse_head}; @@ -83,6 +84,7 @@ sub new def_headers => $def_headers, timeout => $timeout, local_address => $local_address, + ssl_opts => { $ssl_opts ? %$ssl_opts : (verify_hostname => 1) }, use_eval => $use_eval, show_progress=> $show_progress, max_size => $max_size, @@ -582,6 +584,20 @@ sub max_size { shift->_elem('max_siz sub max_redirect { shift->_elem('max_redirect', @_); } sub show_progress{ shift->_elem('show_progress', @_); } +sub ssl_opts { + my $self = shift; + if (@_ == 1) { + my $k = shift; + return $self->{ssl_opts}{$k}; + } + if (@_) { + %{$self->{ssl_opts}} = (%{$self->{ssl_opts}}, @_); + } + else { + return keys %{$self->{ssl_opts}}; + } +} + sub parse_head { my $self = shift; if (@_) { @@ -1040,6 +1056,7 @@ The following options correspond to attr cookie_jar undef default_headers HTTP::Headers->new local_address undef + ssl_opts { verify_hostname => 1 } max_size undef max_redirect 7 parse_head 1