perl - 如何在 Perl 进程之间共享 OpenSSL session ?

标签 perl ssl openssl lwp

我正在使用 Perl 通过 TLS 连接到一些(非常)低功耗的硬件设备。第一次握手大约需要 10-15 秒才能完成!重用 session (来自同一个 Perl 进程)要快得多,但是当下一个作业连接到同一个设备时,新进程必须以相同的延迟建立一个新 session 。我想在我的进程之间共享一个 session 缓存,但我遇到了问题(和段错误!)。

我有一个测试脚本(连接到 openssl s_server -www)和一个使用 Sereal 写缓存的 IO::Socket::SSL::Session_Cache 包装器对象输出到磁盘。尽管在缓存中找到了现有的 session ,它不会重用它们,并且在尝试向缓存中添加其他条目时有时会出现段错误。

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
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

我觉得我快要让它工作了,但我错过了一些东西。

最佳答案

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

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

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

关于perl - 如何在 Perl 进程之间共享 OpenSSL session ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47340354/

相关文章:

java - 如何通过ssl建立web服务客户端

php - 有效函数显示无效

java - 启用身份验证后 NiFi web ui 打不开

perl - 我应该在 Perl 中逐行读取文件时主动释放内存吗?

perl - 有没有办法做到 "reverse".=?

Perl 等效于 (Postgresql BETWEEN 运算符?

regex - Perl 和 Regex - 从 .csv 解析值

azure - 将 SSL 添加到 Azure 门户存储

ssl - DSC - 客户端错误 - 无法获取私钥

ssl - 使用 openssl 创建由中间证书签名的新 TLS 证书