# During setup my $https = IO::Socket::SSL->new( Listen => 128, LocalAddr => '0.0.0.0', LocalPort => 8443, ReuseAddr => 1, SSL_startHandshake => 0, # Don't start SSL negotiation immediately on accept() ); # In the main loop my $client = $https->accept(); # Just a vanilla socket for now really # Now fork off a child process (or use threads or whatever...) # ... # In the child process, negotiate SSL with the client my $client = IO::Socket::SSL->start_SSL($client, SSL_server => 1, SSL_create_ctx_callback => \&ctx_callback, # First callback ); # Now establish an SSL connection with the server and relay traffic in plaintext. # ... # This callback is invoked when a new CTX has been created sub ctx_callback { my $ctx = shift; Net::SSLeay::CTX_set_tlsext_servername_callback($ctx, \&sni_callback); # Second callback } # This callback is invoked during SSL handshake when SNI is known sub sni_callback { my $ssl = shift; my $hostname = Net::SSLeay::get_servername($ssl); # Either use IO::Socket::SSL::Intercept to clone a certificate/key pair # for $hostname or re-use one that was cloned previously my ($cert, $key) = get_cert_key_files($hostname); Net::SSLeay::use_RSAPrivateKey_file($ssl, $key, &Net::SSLeay::FILETYPE_PEM); Net::SSLeay::use_certificate_file($ssl, $cert, &Net::SSLeay::FILETYPE_PEM); # From here on in, SSL handshake should complete with our cloned certificate # if the client has been configured to trust our CA certificate. # Some services depend on their own private CA store and can't be tricked. }