1#!/usr/bin/perl
2
3use strict;
4use vars qw($opt_p $opt_n $opt_bench $opt_debug $opt_version
5	    $opt_v $opt_help
6	    $opt_cert $opt_key $opt_cafile $opt_cadir
7	    );
8use lib qw(lib);
9use Net::SSL;
10use File::Basename;
11use Benchmark;
12
13use Getopt::Long;
14&GetOptions ('p:s' => \$opt_p,
15	     'proxy:s' => \$opt_p,
16	     'bench:n' => \$opt_bench,
17	     'd' => \$opt_debug,
18	     'version:i' => \$opt_version,
19	     'v:i' => \$opt_version,
20	     'h' => \$opt_help,
21	     'help' => \$opt_help,
22	     'cert:s' => \$opt_cert,
23	     'key:s' => \$opt_key,
24	     'CAfile:s' => \$opt_cafile,
25	     'CAdir:s' => \$opt_cadir,
26	     );
27
28my $basename = &File::Basename::basename($0);
29
30# define sub first, in case you are reading the source :)
31sub help {
32
33    print <<HELP;
34Usage: $basename [-d] [-b=NNN] [-h] [-p proxy_name:port] [-CAfile=FILE] [GET|HEAD] [ssl_server_name] [port]
35
36  -d  Debug mode
37  -b  Benchmark NNN times, good test for memory leaks
38  -h  This help message
39  -p  Proxy server, via CONNECT method, localhost:80 format
40
41  -cert  client certificate file
42  -key   private key file
43
44  -CAfile CA certificates file, use certs/ca-bundle.crt for primary root certs
45
46 method          defaults to HEAD
47 ssl_server_name defaults to www.nodeworks.com
48 port            defaults to 443
49
50These are equivalent:
51
52  ./net_ssl_test
53  ./net_ssl_test HEAD www.nodeworks.com 443
54
55This might be how you debug your proxy:
56
57  ./net_ssl_test -d -p http://proxy_name:80 www.nodeworks.com
58
59Note http:// on proxy hostname is stripped off, and is
60meaningless to Crypt::SSLeay.
61
62HELP
63;
64    exit;
65}
66
67if($opt_help) {
68    &help;
69};
70
71if($opt_debug) {
72    eval "use LWP::Debug qw(+)";
73}
74
75my $method = (@ARGV && $ARGV[0] =~ /^[A-Z]+$/) ? shift : "HEAD";
76my($host, $port, $path);
77if($opt_bench) {
78    $host = shift || die("need host, run like ./$basename HEAD yourhost.com.foo");
79} else {
80    $host = shift || "www.nodeworks.com";
81}
82if($host =~ m|^(https://)?([^/:]+)(:(\d+))?(/.*)?$|) {
83    ($host, $port, $path) = ($2, $4, $5);
84}
85
86$port ||= shift || 443;
87$path ||= '/';
88
89if($opt_n) {
90    $ENV{NO_PROXY} = $opt_n;
91}
92
93$ENV{HTTPS_PROXY} = $opt_p;
94$ENV{HTTPS_CERT_FILE} = $opt_cert;
95$ENV{HTTPS_KEY_FILE} = $opt_key;
96
97$opt_cafile && ( $ENV{HTTPS_CA_FILE} = $opt_cafile );
98$opt_cadir  && ( $ENV{HTTPS_CA_DIR} = $opt_cadir   );
99
100if($opt_version) {
101    grep($opt_version eq $_, '2', '3', '23')
102	|| die("$opt_version must be one of 2, 3, or 23");
103    $ENV{HTTPS_VERSION} = $opt_version;
104}
105
106unless(eval { &ssl_connect() }) {
107    print <<OUT;
108== FAILED TO CONNECT ==
109Error: $@
110
111If you need to use a proxy, please pass it in as an argument like
112
113  ./net_ssl_test -p 127.0.0.1:8080
114
115which sets \$ENV{HTTPS_PROXY} for you.
116
117OUT
118    ;
119}
120
121if($opt_bench) {
122    timethis($opt_bench, sub { &ssl_connect() });
123}
124
125
126sub ssl_connect {
127    my $sock = Net::SSL->new(
128			     PeerAddr => $host,
129			     PeerPort => $port,
130			     SSL_Debug => $opt_debug,
131			     Timeout => 15,
132			     );
133    $sock || ($@ ||= "no Net::SSL connection established");
134    my $error = $@;
135    $error && die("Can't connect to $host:$port; $error; $!");
136
137    my $out;
138    $out .= "WEB SITE       : $host:$port\n";
139    $out .= "CIPHER         : ".$sock->get_cipher."\n";
140    my $cert = $sock->get_peer_certificate;
141
142    $out .= "CERT SUBJECT   : ".$cert->subject_name."\n";
143    $out .= "CERTIFIED BY   : ".$cert->issuer_name."\n";
144    $out .= "CERT NOT BEFORE: ".$cert->not_before."\n";
145    $out .= "CERT NOT AFTER : ".$cert->not_after."\n";
146
147    $out .= "\n";
148    $sock->print("$method $path HTTP/1.0\n\n");
149    print $out;
150    $out = '';
151
152    my $buf = '';
153    while ($sock->read($buf, 1024)) {
154	$out .= $buf;
155    }
156
157    unless($opt_bench) {
158	print $out;
159    }
160
161    1;
162}
163
164