1# Various SSL read and write related tests: SSL_read, SSL_peek, SSL_read_ex, 2# SSL_peek_ex, SSL_write_ex, SSL_pending and SSL_has_pending 3 4use lib 'inc'; 5 6use Net::SSLeay; 7use Test::Net::SSLeay qw( 8 can_fork data_file_path initialise_libssl tcp_socket 9); 10 11use Storable; 12 13if (not can_fork()) { 14 plan skip_all => "fork() not supported on this system"; 15} else { 16 plan tests => 53; 17} 18 19initialise_libssl(); 20 21my $pid; 22alarm(30); 23END { kill 9,$pid if $pid } 24 25my $server = tcp_socket(); 26 27# See that lengths differ for all msgs 28my $msg1 = "1 first message from server"; 29my $msg2 = "2 second message from server"; 30my $msg3 = "3 third message from server: pad"; 31 32my @rounds = qw(openssl openssl-1.1.0 openssl-1.1.1); 33 34sub server 35{ 36 # SSL server - just handle connections, send to client and exit 37 my $cert_pem = data_file_path('simple-cert.cert.pem'); 38 my $key_pem = data_file_path('simple-cert.key.pem'); 39 40 defined($pid = fork()) or BAIL_OUT("failed to fork: $!"); 41 if ($pid == 0) { 42 foreach my $round (@rounds) 43 { 44 my ($ctx, $ssl, $cl); 45 46 next if skip_round($round); 47 48 $cl = $server->accept(); 49 50 $ctx = Net::SSLeay::CTX_new(); 51 Net::SSLeay::set_cert_and_key($ctx, $cert_pem, $key_pem); 52 53 $ssl = Net::SSLeay::new($ctx); 54 Net::SSLeay::set_fd($ssl, fileno($cl)); 55 Net::SSLeay::accept($ssl); 56 57 Net::SSLeay::write($ssl, $msg1); 58 Net::SSLeay::write($ssl, $msg2); 59 60 my $msg = Net::SSLeay::read($ssl); 61 Net::SSLeay::write($ssl, $msg); 62 } 63 $server->close(); 64 exit(0); 65 } 66} 67 68sub client 69{ 70 foreach my $round (@rounds) 71 { 72 my ($ctx, $ssl, $cl); 73 74 $cl = $server->connect(); 75 76 $ctx = Net::SSLeay::CTX_new(); 77 $ssl = Net::SSLeay::new($ctx); 78 79 my ($reason, $num_tests) = skip_round($round); 80 if ($reason) { 81 SKIP: { 82 skip($reason, $num_tests); 83 } 84 next; 85 } 86 87 round_openssl($ctx, $ssl, $cl) if $round eq 'openssl'; 88 round_openssl_1_1_0($ctx, $ssl, $cl) if $round eq 'openssl-1.1.0'; 89 round_openssl_1_1_1($ctx, $ssl, $cl) if $round eq 'openssl-1.1.1'; 90 91 Net::SSLeay::shutdown($ssl); 92 Net::SSLeay::free($ssl); 93 } 94 return; 95} 96 97# Returns list for skip() if we should skip this round, false if we 98# shouldn't 99sub skip_round 100{ 101 my ($round) = @_; 102 103 return if $round eq 'openssl'; 104 105 if ($round eq 'openssl-1.1.0') { 106 if (Net::SSLeay::constant("OPENSSL_VERSION_NUMBER") < 0x1010000f || 107 Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER")) 108 { 109 return ("Need OpenSSL 1.1.0 or later", 6); 110 } else { 111 return; 112 } 113 } 114 115 if ($round eq 'openssl-1.1.1') { 116 if (Net::SSLeay::constant("OPENSSL_VERSION_NUMBER") < 0x1010100f || 117 Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER")) 118 { 119 return ("Need OpenSSL 1.1.1 or later", 26); 120 } else { 121 return; 122 } 123 } 124 125 diag("Unknown round: $round"); 126 return; 127} 128 129sub round_openssl 130{ 131 my ($ctx, $ssl, $cl) = @_; 132 133 my ($peek_msg, $read_msg, $len, $err, $ret); 134 135 # ssl is not connected yet 136 $peek_msg = Net::SSLeay::peek($ssl); 137 is($peek_msg, undef, "scalar: peek returns undef for closed ssl"); 138 139 ($peek_msg, $len) = Net::SSLeay::peek($ssl); 140 is($peek_msg, undef, "list: peek returns undef for closed ssl"); 141 cmp_ok($len, '<=', 0, 'list: peek returns length <=0 for closed ssl'); 142 $err = Net::SSLeay::get_error($ssl, $len); 143 isnt($err, Net::SSLeay::ERROR_WANT_READ(), "peek err $err is not retryable WANT_READ"); 144 isnt($err, Net::SSLeay::ERROR_WANT_WRITE(), "peek err $err is not retryable WANT_WRITE"); 145 146 $read_msg = Net::SSLeay::read($ssl); 147 is($read_msg, undef, "scalar: read returns undef for closed ssl"); 148 149 ($read_msg, $len) = Net::SSLeay::read($ssl); 150 is($read_msg, undef, "list: read returns undef for closed ssl"); 151 cmp_ok($len, '<=', 0, 'list: read returns length <=0 for closed ssl'); 152 $err = Net::SSLeay::get_error($ssl, $len); 153 isnt($err, Net::SSLeay::ERROR_WANT_READ(), "read err $err is not retryable WANT_READ"); 154 isnt($err, Net::SSLeay::ERROR_WANT_WRITE(), "read err $err is not retryable WANT_WRITE"); 155 156 $ret = Net::SSLeay::pending($ssl); 157 is($ret, 0, "pending returns 0 for closed ssl"); 158 159 Net::SSLeay::set_fd($ssl, $cl); 160 Net::SSLeay::connect($ssl); 161 162 # msg1 163 $ret = Net::SSLeay::pending($ssl); 164 is($ret, 0, "pending returns 0"); 165 166 $peek_msg = Net::SSLeay::peek($ssl); 167 is($peek_msg, $msg1, "scalar: peek returns msg1"); 168 169 # processing was triggered by peek 170 $ret = Net::SSLeay::pending($ssl); 171 is($ret, length($msg1), "pending returns msg1 length"); 172 173 ($peek_msg, $len) = Net::SSLeay::peek($ssl); 174 is($peek_msg, $msg1, "list: peek returns msg1"); 175 is($len, length($msg1), "list: peek returns msg1 length"); 176 177 $read_msg = Net::SSLeay::read($ssl); 178 is($peek_msg, $read_msg, "scalar: read and peek agree about msg1"); 179 180 # msg2 181 $peek_msg = Net::SSLeay::peek($ssl); 182 is($peek_msg, $msg2, "scalar: peek returns msg2"); 183 184 ($read_msg, $len) = Net::SSLeay::read($ssl); 185 is($peek_msg, $read_msg, "list: read and peek agree about msg2"); 186 is($len, length($msg2), "list: read returns msg2 length"); 187 188 # msg3 189 Net::SSLeay::write($ssl, $msg3); 190 is(Net::SSLeay::read($ssl), $msg3, "ping with msg3"); 191 192 return; 193} 194 195# Test has_pending and other functionality added in 1.1.0. 196# Revisit: Better tests for has_pending 197sub round_openssl_1_1_0 198{ 199 my ($ctx, $ssl, $cl) = @_; 200 201 my ($peek_msg, $read_msg, $len, $err, $ret); 202 203 # ssl is not connected yet 204 $ret = Net::SSLeay::has_pending($ssl); 205 is($ret, 0, "1.1.0: has_pending returns 0 for closed ssl"); 206 207 Net::SSLeay::set_fd($ssl, $cl); 208 Net::SSLeay::connect($ssl); 209 210 # msg1 211 $ret = Net::SSLeay::has_pending($ssl); 212 is($ret, 0, "1.1.0: has_pending returns 0"); 213 214 # This triggers processing after which we have pending data 215 $peek_msg = Net::SSLeay::peek($ssl); 216 is($peek_msg, $msg1, "1.1.0: peek returns msg1"); 217 218 $ret = Net::SSLeay::has_pending($ssl); 219 is($ret, 1, "1.1.0: has_pending returns 1"); 220 221 Net::SSLeay::read($ssl); # Read and discard 222 223 $ret = Net::SSLeay::has_pending($ssl); 224 is($ret, 0, "1.1.0: has_pending returns 0 after read"); 225 226 # msg2 227 Net::SSLeay::read($ssl); # Read and discard 228 229 # msg3 230 Net::SSLeay::write($ssl, $msg3); 231 is(Net::SSLeay::read($ssl), $msg3, "1.1.0: ping with msg3"); 232 233 return; 234} 235 236sub round_openssl_1_1_1 237{ 238 my ($ctx, $ssl, $cl) = @_; 239 240 my ($peek_msg, $read_msg, $len, $err, $err_ex, $ret); 241 242 # ssl is not connected yet 243 ($peek_msg, $ret) = Net::SSLeay::peek_ex($ssl); 244 is($peek_msg, undef, "1.1.1: list: peek_ex returns undef message for closed ssl"); 245 is($ret, 0, '1.1.1: list: peek_ex returns 0 for closed ssl'); 246 $err = Net::SSLeay::get_error($ssl, $ret); 247 isnt($err, Net::SSLeay::ERROR_WANT_READ(), "1.1.1: peek_ex err $err is not retryable WANT_READ"); 248 isnt($err, Net::SSLeay::ERROR_WANT_WRITE(), "1.1.1: peek_ex err $err is not retryable WANT_WRITE"); 249 250 ($read_msg, $len) = Net::SSLeay::read($ssl); 251 is($read_msg, undef, "1.1.1: list: read returns undef message for closed ssl"); 252 cmp_ok($len, '<=', 0, '1.1.1: list: read returns length <=0 for closed ssl'); 253 $err = Net::SSLeay::get_error($ssl, $len); 254 isnt($err, Net::SSLeay::ERROR_WANT_READ(), "1.1.1: read err $err is not retryable WANT_READ"); 255 isnt($err, Net::SSLeay::ERROR_WANT_WRITE(), "1.1.1: read err $err is not retryable WANT_WRITE"); 256 257 ($read_msg, $ret) = Net::SSLeay::read_ex($ssl); 258 is($read_msg, undef, "1.1.1: list: read_ex returns undef message for closed sssl"); 259 is($ret, 0, "1.1.1: list: read_ex returns 0 for closed sssl"); 260 $err_ex = Net::SSLeay::get_error($ssl, $ret); 261 is ($err_ex, $err, '1.1.1: read_ex and read err are equal'); 262 263 Net::SSLeay::set_fd($ssl, $cl); 264 Net::SSLeay::connect($ssl); 265 266 # msg1 267 $ret = Net::SSLeay::has_pending($ssl); 268 is($ret, 0, "1.1.1: has_pending returns 0"); 269 270 # This triggers processing after which we have pending data 271 ($peek_msg, $ret) = Net::SSLeay::peek_ex($ssl); 272 is($peek_msg, $msg1, "1.1.1: list: peek_ex returns msg1"); 273 is($ret, 1, "1.1.1: list: peek_ex returns 1"); 274 275 $len = Net::SSLeay::pending($ssl); 276 is($len, length($msg1), "1.1.1: pending returns msg1 length"); 277 278 $ret = Net::SSLeay::has_pending($ssl); 279 is($ret, 1, "1.1.1: has_pending returns 1"); 280 281 ($read_msg, $ret) = Net::SSLeay::read_ex($ssl); 282 is($read_msg, $msg1, "1.1.1: list: read_ex returns msg1"); 283 is($ret, 1, "1.1.1: list: read_ex returns 1"); 284 285 $len = Net::SSLeay::pending($ssl); 286 is($len, 0, "1.1.1: pending returns 0 after read_ex"); 287 288 $ret = Net::SSLeay::has_pending($ssl); 289 is($ret, 0, "1.1.1: has_pending returns 0 after read_ex"); 290 291 # msg2 292 Net::SSLeay::read($ssl); # Read and discard 293 294 # msg3 295 ($len, $ret) = Net::SSLeay::write_ex($ssl, $msg3); 296 is($len, length($msg3), "1.1.1: write_ex wrote all"); 297 is($ret, 1, "1.1.1: write_ex returns 1"); 298 299 my ($read_msg1, $ret1) = Net::SSLeay::read_ex($ssl, 5); 300 my ($read_msg2, $ret2) = Net::SSLeay::read_ex($ssl, (length($msg3) - 5)); 301 302 is($ret1, 1, '1.1.1: ping with msg3 part1 ok'); 303 is($ret2, 1, '1.1.1: ping with msg3 part2 ok'); 304 is(length($read_msg1), 5, '1.1.1: ping with msg3, part1 length was 5'); 305 is($read_msg1 . $read_msg2, $msg3, "1.1.1: ping with msg3 in two parts"); 306 307 return; 308} 309 310server(); 311client(); 312waitpid $pid, 0; 313exit(0); 314