1package Net::SSL;
2
3use strict;
4use MIME::Base64;
5use Socket;
6use Carp;
7
8use vars qw(@ISA $VERSION $NEW_ARGS);
9$VERSION = '2.86';
10$VERSION = eval $VERSION;
11
12require IO::Socket;
13@ISA=qw(IO::Socket::INET);
14
15my %REAL; # private to this package only
16my $DEFAULT_VERSION = '23';
17my $CRLF = "\015\012";
18my $SEND_USERAGENT_TO_PROXY = 0;
19
20require Crypt::SSLeay;
21
22sub _default_context {
23    require Crypt::SSLeay::MainContext;
24    Crypt::SSLeay::MainContext::main_ctx(@_);
25}
26
27sub _alarm_set {
28    return if $^O eq 'MSWin32' or $^O eq 'NetWare';
29    alarm(shift);
30}
31
32sub new {
33    my($class, %arg) = @_;
34    local $NEW_ARGS = \%arg;
35    $class->SUPER::new(%arg);
36}
37
38sub DESTROY {
39    my $self = shift;
40    delete $REAL{$self};
41    local $@;
42    eval { $self->SUPER::DESTROY; };
43}
44
45sub configure {
46    my($self, $arg) = @_;
47    my $ssl_version = delete $arg->{SSL_Version} ||
48      $ENV{HTTPS_VERSION} || $DEFAULT_VERSION;
49    my $ssl_debug = delete $arg->{SSL_Debug} || $ENV{HTTPS_DEBUG} || 0;
50
51    my $ctx = delete $arg->{SSL_Context} || _default_context($ssl_version);
52
53    *$self->{ssl_ctx} = $ctx;
54    *$self->{ssl_version} = $ssl_version;
55    *$self->{ssl_debug} = $ssl_debug;
56    *$self->{ssl_arg} = $arg;
57    *$self->{ssl_peer_addr} = $arg->{PeerAddr};
58    *$self->{ssl_peer_port} = $arg->{PeerPort};
59    *$self->{ssl_new_arg} = $NEW_ARGS;
60    *$self->{ssl_peer_verify} = 0;
61
62    ## Crypt::SSLeay must also aware the SSL Proxy before calling
63    ## $socket->configure($args). Because the $sock->configure() will
64    ## die when failed to resolve the destination server IP address,
65    ## whether the SSL proxy is used or not!
66    ## - dqbai, 2003-05-10
67    if (my $proxy = $self->proxy) {
68        ($arg->{PeerAddr}, $arg->{PeerPort}) = split(':',$proxy);
69        $arg->{PeerPort} || croak("no port given for proxy server $proxy");
70    }
71
72    $self->SUPER::configure($arg);
73}
74
75# override to make sure there is really a timeout
76sub timeout {
77    shift->SUPER::timeout || 60;
78}
79
80sub blocking {
81    my $self = shift;
82    $self->SUPER::blocking(@_);
83}
84
85sub connect {
86    my $self = shift;
87
88    # configure certs on connect() time, so we can throw an undef
89    # and have LWP understand the error
90    eval { $self->configure_certs() };
91    if($@) {
92        $@ = "configure certs failed: $@; $!";
93        $self->die_with_error($@);
94    }
95
96    # finished, update set_verify status
97    if(my $rv = *$self->{ssl_ctx}->set_verify()) {
98        *$self->{ssl_peer_verify} = $rv;
99    }
100
101    if ($self->proxy) {
102        # don't die() in connect, just return undef and set $@
103        my $proxy_connect = eval { $self->proxy_connect_helper(@_) };
104        if(! $proxy_connect || $@) {
105            $@ = "proxy connect failed: $@; $!";
106            croak($@);
107        }
108    }
109    else {
110        *$self->{io_socket_peername}=@_ == 1 ? $_[0] : IO::Socket::sockaddr_in(@_);
111        if(!$self->SUPER::connect(@_)) {
112            # better to die than return here
113            $@ = "Connect failed: $@; $!";
114            croak($@);
115        }
116    }
117
118    my $debug = *$self->{ssl_debug} || 0;
119    my $ssl = Crypt::SSLeay::Conn->new(*$self->{ssl_ctx}, $debug, $self);
120    my $arg = *$self->{ssl_arg};
121    my $new_arg = *$self->{ssl_new_arg};
122    $arg->{SSL_Debug} = $debug;
123
124    # setup SNI if available
125    $ssl->can("set_tlsext_host_name") and
126        $ssl->set_tlsext_host_name(*$self->{ssl_peer_addr});
127
128    eval {
129        local $SIG{ALRM} = sub { $self->die_with_error("SSL connect timeout") };
130        # timeout / 2 because we have 3 possible connects here
131        _alarm_set($self->timeout / 2);
132
133        my $rv;
134        {
135            local $SIG{PIPE} = \¨
136            $rv = eval { $ssl->connect; };
137        }
138        if (not defined $rv or $rv <= 0) {
139            _alarm_set(0);
140            $ssl = undef;
141            # See RT #59312
142            my %args = (%$arg, %$new_arg);
143            if(*$self->{ssl_version} == 23) {
144                $args{SSL_Version} = 3;
145                # the new connect might itself be overridden with a REAL SSL
146                my $new_ssl = Net::SSL->new(%args);
147                $REAL{$self} = $REAL{$new_ssl} || $new_ssl;
148                return $REAL{$self};
149            }
150            elsif(*$self->{ssl_version} == 3) {
151                # $self->die_with_error("SSL negotiation failed");
152                $args{SSL_Version} = 2;
153                my $new_ssl = Net::SSL->new(%args);
154                $REAL{$self} = $new_ssl;
155                return $new_ssl;
156            }
157			else {
158                # don't die, but do set $@, and return undef
159                eval { $self->die_with_error("SSL negotiation failed") };
160                croak($@);
161            }
162        }
163        _alarm_set(0);
164    };
165
166    # odd error in eval {} block, maybe alarm outside the evals
167    if($@) {
168        $@ = "$@; $!";
169        croak($@);
170    }
171
172    # successful SSL connection gets stored
173    *$self->{ssl_ssl} = $ssl;
174    $self;
175}
176
177# Delegate these calls to the Crypt::SSLeay::Conn object
178sub get_peer_certificate {
179    my $self = shift;
180    $self = $REAL{$self} || $self;
181    *$self->{ssl_ssl}->get_peer_certificate(@_);
182}
183
184sub get_peer_verify {
185    my $self = shift;
186    $self = $REAL{$self} || $self;
187    *$self->{ssl_peer_verify};
188}
189
190sub get_shared_ciphers {
191    my $self = shift;
192    $self = $REAL{$self} || $self;
193    *$self->{ssl_ssl}->get_shared_ciphers(@_);
194}
195
196sub get_cipher {
197    my $self = shift;
198    $self = $REAL{$self} || $self;
199    *$self->{ssl_ssl}->get_cipher(@_);
200}
201
202sub pending {
203    my $self = shift;
204    $self = $REAL{$self} || $self;
205    *$self->{ssl_ssl}->pending(@_);
206}
207
208sub ssl_context {
209    my $self = shift;
210    $self = $REAL{$self} || $self;
211    *$self->{ssl_ctx};
212}
213
214sub die_with_error {
215    my $self=shift;
216    my $reason=shift;
217
218    my @err;
219    while(my $err=Crypt::SSLeay::Err::get_error_string()) {
220       push @err, $err;
221    }
222    croak("$reason: " . join( ' | ', @err ));
223}
224
225sub read {
226    my $self = shift;
227    $self = $REAL{$self} || $self;
228
229    local $SIG{__DIE__} = \&Carp::confess;
230    local $SIG{ALRM} = sub { $self->die_with_error("SSL read timeout") };
231
232    _alarm_set($self->timeout);
233    my $n = *$self->{ssl_ssl}->read(@_);
234    _alarm_set(0);
235    $self->die_with_error("read failed") if !defined $n;
236
237    $n;
238}
239
240sub write {
241    my $self = shift;
242    $self = $REAL{$self} || $self;
243    my $n = *$self->{ssl_ssl}->write(@_);
244    $self->die_with_error("write failed") if !defined $n;
245    $n;
246}
247
248*sysread  = \&read;
249*syswrite = \&write;
250
251sub print {
252    my $self = shift;
253    $self = $REAL{$self} || $self;
254    # should we care about $, and $\??
255    # I think it is too expensive...
256    $self->write(join("", @_));
257}
258
259sub printf {
260    my $self = shift;
261    $self = $REAL{$self} || $self;
262    my $fmt = shift;
263    $self->write(sprintf($fmt, @_));
264}
265
266sub getchunk {
267    my $self = shift;
268    $self = $REAL{$self} || $self;
269    my $buf = '';  # warnings
270    my $n = $self->read($buf, 32768);
271    return unless defined $n;
272    $buf;
273}
274
275# This is really inefficient, but we only use it for reading the proxy response
276# so that does not really matter.
277sub getline {
278    my $self = shift;
279    $self = $REAL{$self} || $self;
280    my $val="";
281    my $buf;
282    do {
283        $self->SUPER::recv($buf, 1);
284        $val .= $buf;
285    } until ($buf eq "\n");
286
287    $val;
288}
289
290# XXX: no way to disable <$sock>??  (tied handle perhaps?)
291
292sub get_lwp_object {
293    my $self = shift;
294
295    my $lwp_object;
296    my $i = 0;
297    while(1) {
298        package DB;
299        my @stack = caller($i++);
300        last unless @stack;
301        my @stack_args = @DB::args;
302        my $stack_object = $stack_args[0] || next;
303        return $stack_object
304            if ref($stack_object)
305                and $stack_object->isa('LWP::UserAgent');
306    }
307    return undef;
308}
309
310sub send_useragent_to_proxy {
311    if (my $val = shift) {
312        $SEND_USERAGENT_TO_PROXY = $val;
313    }
314    return $SEND_USERAGENT_TO_PROXY;
315}
316
317sub proxy_connect_helper {
318    my $self = shift;
319
320    my $proxy = $self->proxy;
321    my ($proxy_host, $proxy_port) = split(':',$proxy);
322    $proxy_port || croak("no port given for proxy server $proxy");
323
324    my $proxy_addr = gethostbyname($proxy_host);
325    $proxy_addr || croak("can't resolve proxy server name: $proxy_host, $!");
326
327    my($peer_port, $peer_addr) = (*$self->{ssl_peer_port}, *$self->{ssl_peer_addr});
328    $peer_addr || croak("no peer addr given");
329    $peer_port || croak("no peer port given");
330
331    # see if the proxy should be bypassed
332    my @no_proxy = split( /\s*,\s*/, $ENV{NO_PROXY} || $ENV{no_proxy} || '');
333    my $is_proxied = 1;
334    my $domain;
335    for $domain (@no_proxy) {
336        if ($peer_addr =~ /\Q$domain\E$/) {
337            $is_proxied = 0;
338            last;
339        }
340    }
341
342    if ($is_proxied) {
343        $self->SUPER::connect($proxy_port, $proxy_addr)
344          || croak("proxy connect to $proxy_host:$proxy_port failed: $!");
345    }
346    else {
347        # see RT #57836
348        my $peer_addr_packed = gethostbyname($peer_addr);
349        $self->SUPER::connect($peer_port, $peer_addr_packed)
350          || croak("proxy bypass to $peer_addr:$peer_addr failed: $!");
351    }
352
353    my $connect_string;
354    if ($ENV{"HTTPS_PROXY_USERNAME"} || $ENV{"HTTPS_PROXY_PASSWORD"}) {
355        my $user = $ENV{"HTTPS_PROXY_USERNAME"};
356        my $pass = $ENV{"HTTPS_PROXY_PASSWORD"};
357
358        my $credentials = encode_base64("$user:$pass", "");
359        $connect_string = join($CRLF,
360            "CONNECT $peer_addr:$peer_port HTTP/1.0",
361            "Proxy-authorization: Basic $credentials"
362        );
363    }
364    else {
365        $connect_string = "CONNECT $peer_addr:$peer_port HTTP/1.0";
366    }
367    $connect_string .= $CRLF;
368
369    if (send_useragent_to_proxy()) {
370        my $lwp_object = $self->get_lwp_object;
371        if($lwp_object && $lwp_object->agent) {
372            $connect_string .= "User-Agent: ".$lwp_object->agent.$CRLF;
373        }
374    }
375
376    $connect_string .= $CRLF;
377    $self->SUPER::send($connect_string);
378
379    my $timeout;
380    my $header = '';
381
382    # See RT #33954
383    # See also RT #64054
384    # Handling incomplete reads and writes better (for some values of
385    # better) may actually make this problem go away, but either way,
386    # there is no good reason to use \d when checking for 0-9
387
388    while ($header !~ m{HTTP/[0-9][.][0-9]\s+200\s+.*$CRLF$CRLF}s) {
389        $timeout = $self->timeout(5) unless length $header;
390        my $n = $self->SUPER::sysread($header, 8192, length $header);
391        last if $n <= 0;
392    }
393
394    $self->timeout($timeout) if defined $timeout;
395    my $conn_ok = ($header =~ m{HTTP/[0-9]+[.][0-9]+\s+200\s+}is) ? 1 : 0;
396
397    if (not $conn_ok) {
398        croak("PROXY ERROR HEADER, could be non-SSL URL:\n$header");
399    }
400
401    $conn_ok;
402}
403
404# code adapted from LWP::UserAgent, with $ua->env_proxy API
405# see also RT #57836
406sub proxy {
407    my $self = shift;
408    my $proxy_server = $ENV{HTTPS_PROXY} || $ENV{https_proxy};
409    return unless $proxy_server;
410
411    my($peer_port, $peer_addr) = (
412        *$self->{ssl_peer_port},
413        *$self->{ssl_peer_addr}
414    );
415    $peer_addr || croak("no peer addr given");
416    $peer_port || croak("no peer port given");
417
418    # see if the proxy should be bypassed
419    my @no_proxy = split( /\s*,\s*/,
420        $ENV{NO_PROXY} || $ENV{no_proxy} || ''
421    );
422    my $is_proxied = 1;
423    for my $domain (@no_proxy) {
424        if ($peer_addr =~ /\Q$domain\E\z/) {
425            return;
426        }
427    }
428
429    $proxy_server =~ s|\Ahttps?://||i;
430    # sanitize the end of the string too
431    # see also http://www.nntp.perl.org/group/perl.libwww/2012/10/msg7629.html
432    # and https://github.com/nanis/Crypt-SSLeay/pull/1
433    # Thank you Mark Allen and YigangX Wen
434    $proxy_server =~ s|(:[1-9][0-9]{0,4})/\z|$1|;
435    $proxy_server;
436}
437
438sub configure_certs {
439    my $self = shift;
440    my $ctx = *$self->{ssl_ctx};
441
442    my $count = 0;
443    for (qw(HTTPS_PKCS12_FILE HTTPS_CERT_FILE HTTPS_KEY_FILE)) {
444        my $file = $ENV{$_};
445        if ($file) {
446            (-e $file) or croak("$file file does not exist: $!");
447            (-r $file) or croak("$file file is not readable");
448            $count++;
449            if (/PKCS12/) {
450                $count++;
451                $ctx->use_pkcs12_file($file ,$ENV{'HTTPS_PKCS12_PASSWORD'}) || croak("failed to load $file: $!");
452                last;
453            }
454            elsif (/CERT/) {
455                $ctx->use_certificate_file($file ,1) || croak("failed to load $file: $!");
456            }
457            elsif (/KEY/) {
458                $ctx->use_PrivateKey_file($file, 1) || croak("failed to load $file: $!");
459            }
460            else {
461                croak("setting $_ not supported");
462            }
463        }
464    }
465
466    # if both configs are set, then verify them
467    if ($count == 2) {
468        if (! $ctx->check_private_key) {
469            croak("Private key and certificate do not match");
470        }
471    }
472
473    $count; # number of successful cert loads/checks
474}
475
476sub accept   { shift->_unimpl("accept") }
477sub getc     { shift->_unimpl("getc")   }
478sub ungetc   { shift->_unimpl("ungetc") }
479sub getlines { shift->_unimpl("getlines"); }
480
481sub _unimpl {
482    my($self, $meth) = @_;
483    croak("$meth not implemented for Net::SSL sockets");
484}
485
4861;
487
488__END__
489
490=head1 NAME
491
492Net::SSL - support for Secure Sockets Layer
493
494=head1 METHODS
495
496=over 4
497
498=item new
499
500Creates a new C<Net::SSL> object.
501
502=item configure
503
504Configures a C<Net::SSL> socket for operation.
505
506=item configure_certs
507
508Sets up a certificate file to use for communicating with on
509the socket.
510
511=item connect
512
513=item die_with_error
514
515=item get_cipher
516
517=item get_lwp_object
518
519Walks up the caller stack and looks for something blessed into
520the C<LWP::UserAgent> namespace and returns it. Vaguely deprecated.
521
522=item get_peer_certificate
523
524Gets the peer certificate from the underlying C<Crypt::SSLeay::Conn>
525object.
526
527=item get_peer_verify
528
529=item get_shared_ciphers
530
531=item getchunk
532
533Attempts to read up to 32KiB of data from the socket. Returns
534C<undef> if nothing was read, otherwise returns the data as
535a scalar.
536
537=item pending
538
539Provides access to OpenSSL's C<pending> attribute on the SSL connection
540object.
541
542=item getline
543
544Reads one character at a time until a newline is encountered,
545and returns the line, including the newline. Grossly
546inefficient.
547
548=item print
549
550Concatenates the input parameters and writes them to the socket.
551Does not honour C<$,> nor C<$/>. Returns the number of bytes written.
552
553=item printf
554
555Performs a C<sprintf> of the input parameters (thus, the first
556parameter must be the format), and writes the result to the socket.
557Returns the number of bytes written.
558
559=item proxy
560
561Returns the hostname of an https proxy server, as specified by the
562C<HTTPS_PROXY> environment variable.
563
564=item proxy_connect_helper
565
566Helps set up a connection through a proxy.
567
568=item read
569
570Performs a read on the socket and returns the result.
571
572=item ssl_context
573
574=item sysread
575
576Is an alias of C<read>.
577
578=item timeout
579
580Returns the timeout value of the socket as defined by the implementing
581class or 60 seconds by default.
582
583=item blocking
584
585Returns a boolean indicating whether the underlying socket is in
586blocking mode. By default, Net::SSL sockets are in blocking mode.
587
588    $sock->blocking(0); # set to non-blocking mode
589
590This method simply calls the underlying C<blocking> method of the
591IO::Socket object.
592
593=item write
594
595Writes the parameters passed in (thus, a list) to the socket. Returns
596the number of bytes written.
597
598=item syswrite
599
600Is an alias of C<write>.
601
602=item accept
603
604Not yet implemented. Will die if called.
605
606=item getc
607
608Not yet implemented. Will die if called.
609
610=item getlines
611
612Not yet implemented. Will die if called.
613
614=item ungetc
615
616Not yet implemented. Will die if called.
617
618=item send_useragent_to_proxy
619
620By default (as of version 2.80 of C<Net::SSL> in the 0.54 distribution
621of Crypt::SSLeay), the user agent string is no longer sent to the
622proxy (but will continue to be sent to the remote host).
623
624The previous behaviour was of marginal benefit, and could cause
625fatal errors in certain scenarios (see CPAN bug #4759) and so no
626longer happens by default.
627
628To reinstate the old behaviour, call C<Net::SSL::send_useragent_to_proxy>
629with a true value (usually 1).
630
631=back
632
633=head1 DIAGNOSTICS
634
635  "no port given for proxy server <proxy>"
636
637A proxy was specified for configuring a socket, but no port number
638was given. Ensure that the proxy is specified as a host:port pair,
639such as C<proxy.example.com:8086>.
640
641  "configure certs failed: <contents of $@>; <contents of $!>"
642
643  "proxy connect failed: <contents of $@>; <contents of $!>"
644
645  "Connect failed: <contents of $@>; <contents of $!>"
646
647During connect().
648
649=head2 SEE ALSO
650
651=over 4
652
653=item IO::Socket::INET
654
655C<Net::SSL> is implemented by subclassing C<IO::Socket::INET>, hence
656methods not specifically overridden are defined by that package.
657
658=item Net::SSLeay
659
660A package that provides a Perl-level interface to the C<openssl>
661secure sockets layer library.
662
663=back
664
665=cut
666
667