Re: non-blocking example for Net::SSLeay

2001-04-30 Thread Eric Rescorla

[EMAIL PROTECTED] writes:
 I'm trying to write a tiny SSL webserver.  It would really
 help to have an example of how to set up and use non-blocking
 SSL calls with a select statement or similar.  The problem
 here is implementing CGI: the CGI script wants normal I/O
 through normal file descriptiors, and I see that it's my
 job to do SSL_read and copy the result into that file
 descriptor, and copy output from the CGI script into SSL_write.
 
 I need to select() on the CGI processes output pipe, and the
 SSL input pipe, and service requests as they come in.
The sample code from my book on SSL includes a program that
uses select() on the terminal and on the SSL input pipe, which
is a pretty isomorphic problem. You can download it at:

http://www.rtfm.com/sslbook/examples/

 Does the underlying BIO interface mean if I do a fcntl
 O_NONBLOCK on the NS (network socket) that SSL will somehow
 figure that out? 
Yes. The errors bubble up the stack to the SSL library.

 Maybe a new call: SSL_select($ssl,$readfds,$writefds,$exceptfds,$timeout)
 what it might do internally is do a select on the ssl network
 socket read and the rest of the $readfs, but loop around and
 try again if the network socket read didn't complete a pending
 SSL_read? 
You could do this, but it would interfere with other pieces
of software that want to run the event loop (X programs, for
instance, often want to).

 Can  SSL writes not be similarly monitored,
 they can just be set as nonblocking?
The basic problem you're facing is that SSL reads and writes must
happen at record boundaries, so, for instance, just because there's
data on the pipe doesn't mean that an entire record is ready to read.
Your program really has to be prepared to handle the situation where
even though select() says things are ready, they're not.  There's
pretty extensive discussion of the details of using select() with
OpenSSL in Chapter 8 of my book, which also (of course) includes
extensive documentation of the aforementioned sample code.

-Ekr

[Eric Rescorla   [EMAIL PROTECTED]]
Author of SSL and TLS: Designing and Building Secure Systems
  http://www.rtfm.com/
__
OpenSSL Project http://www.openssl.org
User Support Mailing List[EMAIL PROTECTED]
Automated List Manager   [EMAIL PROTECTED]



Re: non-blocking example for Net::SSLeay

2001-04-30 Thread Noel Burton-Krahn

Hi M,

Here's a test program which negotiates an SSL connection and sends
data in a single process (no threads, all async IO).  

I've also included a patch for Net-SSLeay-1.06.  I had to add a few
macros to Net::SSLeay to support the async error returns.  I also
fixed the makefile to detect openssl.exe under Windows.

Hope it helps.

--Noel

 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Subject: non-blocking example for Net::SSLeay
 Date: Sun, 29 Apr 2001 17:59:46 -0700 (PDT)
 
 
 I'm trying to write a tiny SSL webserver.  It would really
 help to have an example of how to set up and use non-blocking
 SSL calls with a select statement or similar.  The problem
 here is implementing CGI: the CGI script wants normal I/O
 through normal file descriptiors, and I see that it's my
 job to do SSL_read and copy the result into that file
 descriptor, and copy output from the CGI script into SSL_write.
 
 I need to select() on the CGI processes output pipe, and the
 SSL input pipe, and service requests as they come in.
 
 I'm writing this in perl, using Net::SSLeay.  I've patched
 the echo example code into my tiny webserver, so if I'm
 doing the SSL_reads and SSL_writes in the main process, it works,
 but of course, the cgi part fails miserably.
 
 Does the underlying BIO interface mean if I do a fcntl
 O_NONBLOCK on the NS (network socket) that SSL will somehow
 figure that out?   I don't see a BIO_set sort of thing
 to set nonblocking behavior for the BIO or SSL.   The
 docs are a bit sparse, here.
 
 Maybe a new call: SSL_select($ssl,$readfds,$writefds,$exceptfds,$timeout)
 what it might do internally is do a select on the ssl network
 socket read and the rest of the $readfs, but loop around and
 try again if the network socket read didn't complete a pending
 SSL_read?  Can  SSL writes not be similarly monitored,
 they can just be set as nonblocking?




#! /usr/bin/perl -w

use lib '../lib';
use Socket;
use QV::OS;
use Net::SSLeay qw(1.07 die_now die_if_ssl_error);
Net::SSLeay::load_error_strings();
Net::SSLeay::SSLeay_add_ssl_algorithms();
Net::SSLeay::randomize();

use strict;

sub ssl_ctx {
my($io) = @_;
my($ctx, $ssl);

$ctx = Net::SSLeay::CTX_new() or die_now(Failed to create SSL_CTX $!);
Net::SSLeay::CTX_set_options($ctx, Net::SSLeay::OP_ALL)
and die_if_ssl_error(CTX_set_options);
$ssl = Net::SSLeay::new($ctx) or die_now(Failed to create SSL $!);
Net::SSLeay::set_fd($ssl, fileno($io))
and die_if_ssl_error(set_fd);
return $ssl;
}

sub ssl_err_select {
my($ret, $ssl, $io, $sel_read, $sel_write) = @_;
my($i);
my($fileno) = fileno($io);

vec($$sel_read, $fileno, 1) = 0;
vec($$sel_write, $fileno, 1) = 0;

if( $ret  0 ) {
$i = Net::SSLeay::get_error($ssl, $ret);
if( $i == Net::SSLeay::ERROR_WANT_READ ) {

# debug
print(ERROR_WANT_READ: fileno= . fileno($io) . \n);

vec($$sel_read, $fileno, 1) = 1;
$ret = undef;
}
elsif( $i == Net::SSLeay::ERROR_WANT_WRITE ) {

# debug
print(ERROR_WANT_WRITE: fileno= . fileno($io) . \n);

vec($$sel_write, $fileno, 1) = 1;
$ret = undef;
}
}
return $ret;
}

#-
my($buf, $off);

$off = 0;
if( @ARGV || ! -t STDIN ) {
local($/) = undef;
$buf = ;
}
else {
$buf = Hello from Alice;
}


my($ssl_A, $connect_A, 
   $ssl_B, $accept_B,
   $rfds, $wfds, $sel_read, $sel_write,
   $s, $i, $x);

($a, $b) = QV::OS-socket_pair();
select($a); $|=1; 
select($b); $|=1; 
select(STDOUT);

QV::OS-io_nonblock($a, 1);
QV::OS-io_nonblock($b, 1);

# debug
print(fileno(A)=, fileno($a), \n);
print(fileno(B)=, fileno($b), \n);

$ssl_A = ssl_ctx($a);
#Net::SSLeay::set_connect_state($ssl_A);
Net::SSLeay::use_RSAPrivateKey_file($ssl_A, 'b-rsa.pem',
Net::SSLeay::FILETYPE_PEM);
die_if_ssl_error(private key);
Net::SSLeay::use_certificate_file($ssl_A, 'b-cert.pem',
   Net::SSLeay::FILETYPE_PEM);
die_if_ssl_error(certificate);


$ssl_B = ssl_ctx($b);
#Net::SSLeay::set_connect_state($ssl_B);
Net::SSLeay::use_RSAPrivateKey_file($ssl_B, 'b-rsa.pem',
Net::SSLeay::FILETYPE_PEM);
die_if_ssl_error(private key);
Net::SSLeay::use_certificate_file($ssl_B, 'b-cert.pem',
   Net::SSLeay::FILETYPE_PEM);
die_if_ssl_error(certificate);


$accept_B = $connect_A = undef;
$rfds = $wfds = '';
vec($rfds, fileno($a), 1) = 1;
vec($rfds, fileno($b), 1) = 1;
$sel_read = $sel_write = '';

while(1) {
if( vec($rfds, fileno($a), 1)
|| vec($wfds, fileno($a), 1) 
) {
if( !$connect_A ) {
$i = Net::SSLeay::connect($ssl_A);
$i = ssl_err_select($i, $ssl_A, $a, \$sel_read, \$sel_write);
if( !defined($i) ) {
# no error, just continue