我该如何在Perl进程之间共享OpenSSL会话?

3
我正在使用Perl连接一些(非常)低功率的硬件设备进行TLS通信。第一次握手可能需要10-15秒才能完成!从同一个Perl进程中重用会话(session)会更快,但是当下一个作业需要连接到同一个设备时,新进程必须建立一个新的具有相同延迟的会话。我希望能够在我的进程之间共享一个会话缓存,但是我遇到了一些问题(和段错误!)。
我有一个测试脚本(连接到openssl s_server -www),其中包含一个使用Sereal将缓存对象写入磁盘的IO::Socket::SSL::Session_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;
}

输出:

 rm -f /tmp/ssl-session-cache && perl wes.swp/workbench.pl
发起请求
获取本地主机:4433的会话
创建新缓存
添加本地主机:4433的会话-23864624
> SSL-Session:
>     Session-ID: 
>     Session-ID-ctx: 01000000
>     Master-Key: DDF335492BFE2A7BA7674A656E72005865859D89249D597302F338D01C5776E2C94B61E6BCBED6114DFDA5AAEECD22EA
发起请求
获取本地主机:4433的会话
从文件中获取缓存,IO::Socket::SSL::Session_Cache
找到会话23864624
添加本地主机:4433的会话-23864624 # 尝试重新添加会话??
> SSL-Session:
>     Session-ID: 
>     Session-ID-ctx: 01000000
>     Master-Key: 4FE17B7FE9B4DE0A711C659FC333F686AD41840740B9D10E67A972D5A27D1720F0470329DA63DE65C1B023A1E2F0CC89
发起请求
获取本地主机:4433的会话
从文件中获取缓存,IO::Socket::SSL::Session_Cache
找到会话23864624
添加本地主机:4433的会话-23864624
> SSL-Session:
>     Session-ID: 
>     Session-ID-ctx: 01000000
>     Master-Key: C76C52E5ECC13B0BB4FA887B381779B6F686A73DDFBEA06B33336537EC6AE39290370C07505BCD8B552CA874CD6E4089

我感觉离让它正常工作很近了,但我似乎还缺少什么。


3
作为完全不同的方法,需要一个负责与设备进行所有通信的服务。 - ysth
1个回答

3

我认为在进程之间使用IO::Socket::SSL/Net::SSLeay或Crypt::SSLeay(它们是LWP的较新和较旧的SSL后端)的方法不存在。

您正在尝试在代码中使用的会话缓存引用了OpenSSL库内部的SESSION对象。在Perl级别对缓存进行序列化不会序列化来自OpenSSL库内部的部分,而只会包括指向内部结构的指针。由于这些指针仅对当前进程状态有效,因此在不同的进程或进程状态下再次反序列化将导致悬空指针指向最好情况下的无处或最坏情况下的其他数据,从而导致段错误或内部数据损坏。

在Net::SSLeay中,有i2d_SSL_SESSION和d2i_SSL_SESSION函数,理论上可以用于正确序列化SESSION对象。但我怀疑它们在当前实现中是否可用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接