I'm using Perl to connect to some (very) low-powered hardware devices with TLS. The first handshake can take around 10-15 seconds to complete! Reusing the session (from the same Perl process) is much faster but when the next job comes around to connect to the same device the new process has to establish a new session with the same delay. I'd like to share a session cache between my processes but I'm running into problems (and segfaults!).
I have a test script (connecting to openssl s_server -www
) with a IO::Socket::SSL::Session_Cache
wrapper that uses Sereal to write the cache object out to disk. Despite finding the existing sessions in the cache, it does not reuse them and sometimes segfaults when trying to add additional entries to the cache.
use 5.20.1; use warnings;
use LWP::UserAgent;
use IO::Socket::SSL;
# $IO::Socket::SSL::DEBUG = 2;
request_with_new_ua();
request_with_new_ua();
request_with_new_ua();
sub request_with_new_ua {
say "make request";
my $ua = LWP::UserAgent->new;
$ua->ssl_opts(
verify_hostname => 0,
SSL_session_cache => Inline::SessionStore->new,
);
process_response($ua->get('https://localhost:4433'));
}
sub process_response {
my $res = shift;
say "> $_" for grep /Session|Master/, split /\n/, $res->as_string;
}
BEGIN {
package Inline::SessionStore;
use 5.20.1; use warnings;
use Moo;
use experimental qw(signatures);
use Sereal::Encoder;
use Sereal::Decoder;
use Try::Tiny;
use Path::Tiny;
has session_cache => ( is => 'rw' );
my $encoder = Sereal::Encoder->new;
my $decoder = Sereal::Decoder->new;
my $file = path('/tmp/ssl-session-cache');
sub get_session ($self, $key) {
say "get session $key";
my $cache;
try {
$cache = $decoder->decode($file->slurp_raw);
say "got cache from file, ".ref $cache;
} catch {
say $_ unless /No such file/;
$cache = IO::Socket::SSL::Session_Cache->new(128);
say "made new cache";
};
$self->session_cache($cache);
my $ret = $cache->get_session($key);
say "found session $ret" if $ret;
return $ret;
}
sub add_session {
my $self = shift;
say"add session " . join ' - ', @_;
my $session = $self->session_cache->add_session(@_);
$file->spew_raw($encoder->encode($self->session_cache));
return $session;
}
sub del_session {
my $self = shift;
say "del session " . join ' - ', @_;
$self->session_cache->del_session(@_);
$file->spew_raw($encoder->encode($self->session_cache));
}
1;
}
And output:
rm -f /tmp/ssl-session-cache && perl wes.swp/workbench.pl make request get session localhost:4433 made new cache add session localhost:4433 - 23864624 > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: DDF335492BFE2A7BA7674A656E72005865859D89249D597302F338D01C5776E2C94B61E6BCBED6114DFDA5AAEECD22EA make request get session localhost:4433 got cache from file, IO::Socket::SSL::Session_Cache found session 23864624 add session localhost:4433 - 23864624 # trying to re-add the session?? > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: 4FE17B7FE9B4DE0A711C659FC333F686AD41840740B9D10E67A972D5A27D1720F0470329DA63DE65C1B023A1E2F0CC89 make request get session localhost:4433 got cache from file, IO::Socket::SSL::Session_Cache found session 23864624 add session localhost:4433 - 23864624 > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: C76C52E5ECC13B0BB4FA887B381779B6F686A73DDFBEA06B33336537EC6AE39290370C07505BCD8B552CA874CD6E4089
I feel like I'm close to getting this to work but I'm missing something.