1b8851fccSafresh1#!perl 2b8851fccSafresh1 3b8851fccSafresh1use 5.008001; 4b8851fccSafresh1 5b8851fccSafresh1use strict; 6b8851fccSafresh1use warnings; 7b8851fccSafresh1 8*256a93a4Safresh1use Test::More; 9*256a93a4Safresh1 10*256a93a4Safresh1BEGIN { 11*256a93a4Safresh1 if (!eval { require Socket }) { 12*256a93a4Safresh1 plan skip_all => "no Socket"; 13*256a93a4Safresh1 } 14*256a93a4Safresh1 elsif (ord('A') == 193 && !eval { require Convert::EBCDIC }) { 15*256a93a4Safresh1 plan skip_all => "EBCDIC but no Convert::EBCDIC"; 16*256a93a4Safresh1 } 17*256a93a4Safresh1} 18*256a93a4Safresh1 19b8851fccSafresh1use Config; 20b8851fccSafresh1use File::Temp 'tempfile'; 21b8851fccSafresh1use Net::POP3; 22b8851fccSafresh1 23b8851fccSafresh1my $debug = 0; # Net::POP3 Debug => .. 24b8851fccSafresh1 25b8851fccSafresh1my $parent = 0; 26b8851fccSafresh1 27b8851fccSafresh1plan skip_all => "no SSL support found in Net::POP3" if ! Net::POP3->can_ssl; 28b8851fccSafresh1 29b8851fccSafresh1plan skip_all => "fork not supported on this platform" 30b8851fccSafresh1 unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} || 31b8851fccSafresh1 (($^O eq 'MSWin32' || $^O eq 'NetWare') and 32b8851fccSafresh1 $Config::Config{useithreads} and 33b8851fccSafresh1 $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/); 34b8851fccSafresh1 35b8851fccSafresh1my $srv = IO::Socket::INET->new( 36b8851fccSafresh1 LocalAddr => '127.0.0.1', 37b8851fccSafresh1 Listen => 10 38b8851fccSafresh1); 39b8851fccSafresh1plan skip_all => "cannot create listener on localhost: $!" if ! $srv; 40b8851fccSafresh1my $saddr = $srv->sockhost.':'.$srv->sockport; 41b8851fccSafresh1 42b8851fccSafresh1plan tests => 2; 43b8851fccSafresh1 44b8851fccSafresh1require IO::Socket::SSL::Utils; 45b8851fccSafresh1my ($ca,$key) = IO::Socket::SSL::Utils::CERT_create( CA => 1 ); 46b8851fccSafresh1my ($fh,$cafile) = tempfile(); 47b8851fccSafresh1print $fh IO::Socket::SSL::Utils::PEM_cert2string($ca); 48b8851fccSafresh1close($fh); 49b8851fccSafresh1 50b8851fccSafresh1$parent = $$; 51b8851fccSafresh1END { unlink($cafile) if $$ == $parent } 52b8851fccSafresh1 53b8851fccSafresh1my ($cert) = IO::Socket::SSL::Utils::CERT_create( 54b8851fccSafresh1 subject => { CN => 'pop3.example.com' }, 55b8851fccSafresh1 issuer_cert => $ca, issuer_key => $key, 56b8851fccSafresh1 key => $key 57b8851fccSafresh1); 58b8851fccSafresh1 59b8851fccSafresh1test(1); # direct ssl 60b8851fccSafresh1test(0); # starttls 61b8851fccSafresh1 62b8851fccSafresh1 63b8851fccSafresh1sub test { 64b8851fccSafresh1 my $ssl = shift; 65b8851fccSafresh1 defined( my $pid = fork()) or die "fork failed: $!"; 66b8851fccSafresh1 exit(pop3_server($ssl)) if ! $pid; 67b8851fccSafresh1 pop3_client($ssl); 68b8851fccSafresh1 wait; 69b8851fccSafresh1} 70b8851fccSafresh1 71b8851fccSafresh1 72b8851fccSafresh1sub pop3_client { 73b8851fccSafresh1 my $ssl = shift; 74b8851fccSafresh1 my %sslopt = ( 75b8851fccSafresh1 SSL_verifycn_name => 'pop3.example.com', 76b8851fccSafresh1 SSL_ca_file => $cafile 77b8851fccSafresh1 ); 78b8851fccSafresh1 $sslopt{SSL} = 1 if $ssl; 79b8851fccSafresh1 my $cl = Net::POP3->new($saddr, %sslopt, Debug => $debug); 80b8851fccSafresh1 note("created Net::POP3 object"); 81b8851fccSafresh1 if (!$cl) { 82b8851fccSafresh1 fail( ($ssl ? "SSL ":"" )."POP3 connect failed"); 83b8851fccSafresh1 } elsif ($ssl) { 84b8851fccSafresh1 $cl->quit; 85b8851fccSafresh1 pass("SSL POP3 connect success"); 86b8851fccSafresh1 } elsif ( ! $cl->starttls ) { 87b8851fccSafresh1 no warnings 'once'; 88b8851fccSafresh1 fail("starttls failed: $IO::Socket::SSL::SSL_ERROR"); 89b8851fccSafresh1 } else { 90b8851fccSafresh1 $cl->quit; 91b8851fccSafresh1 pass("starttls success"); 92b8851fccSafresh1 } 93b8851fccSafresh1} 94b8851fccSafresh1 95b8851fccSafresh1sub pop3_server { 96b8851fccSafresh1 my $ssl = shift; 97b8851fccSafresh1 my $cl = $srv->accept or die "accept failed: $!"; 98b8851fccSafresh1 my %sslargs = ( 99b8851fccSafresh1 SSL_server => 1, 100b8851fccSafresh1 SSL_cert => $cert, 101b8851fccSafresh1 SSL_key => $key, 102b8851fccSafresh1 ); 103b8851fccSafresh1 if ( $ssl ) { 104b8851fccSafresh1 if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) { 105b8851fccSafresh1 diag("initial ssl handshake with client failed"); 106b8851fccSafresh1 return; 107b8851fccSafresh1 } 108b8851fccSafresh1 } 109b8851fccSafresh1 110b8851fccSafresh1 print $cl "+OK localhost ready\r\n"; 111b8851fccSafresh1 while (<$cl>) { 112b8851fccSafresh1 my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_; 113b8851fccSafresh1 $cmd = uc($cmd); 114b8851fccSafresh1 if ($cmd eq 'QUIT' ) { 115b8851fccSafresh1 print $cl "+OK bye\r\n"; 116b8851fccSafresh1 last; 117b8851fccSafresh1 } elsif ( $cmd eq 'CAPA' ) { 118b8851fccSafresh1 print $cl "+OK\r\n". 119b8851fccSafresh1 ( $ssl ? "" : "STLS\r\n" ). 120b8851fccSafresh1 ".\r\n"; 121b8851fccSafresh1 } elsif ( ! $ssl and $cmd eq 'STLS' ) { 122b8851fccSafresh1 print $cl "+OK starting ssl\r\n"; 123b8851fccSafresh1 if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) { 124b8851fccSafresh1 diag("initial ssl handshake with client failed"); 125b8851fccSafresh1 return; 126b8851fccSafresh1 } 127b8851fccSafresh1 $ssl = 1; 128b8851fccSafresh1 } else { 129b8851fccSafresh1 diag("received unknown command: $cmd"); 130b8851fccSafresh1 print "-ERR unknown cmd\r\n"; 131b8851fccSafresh1 } 132b8851fccSafresh1 } 133b8851fccSafresh1 134b8851fccSafresh1 note("POP3 dialog done"); 135b8851fccSafresh1} 136