在此脚本中如何以及在何处调用 OpenSSL?

Posted

技术标签:

【中文标题】在此脚本中如何以及在何处调用 OpenSSL?【英文标题】:How and Where is OpenSSL called in this script? 【发布时间】:2017-03-02 22:28:54 【问题描述】:

centos-6.8 perl, v5.10.1 (*) 为 x86_64-linux-thread-multi 构建

我正在尝试更新名为 CSP 的 Perl 脚本。我对脚本的经验仅限于在我们需要新服务器证书的极少数情况下运行它。我联系了原剧本的作者 Leif Johansson,但没有收到回复。我目前正在做的修改后的项目可以在https://github.com/byrnejb/rcsp/tree/csp040找到。

这就是背景。我的 Perl 编程经验可以忽略不计。因此,我在这里的问题可能很幼稚。

我在./blib/lib/CSP.pm中有这些代码片段:

. . .
package CSP;

use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;
require AutoLoader;
use IO::File;
use Term::Prompt;
use POSIX qw(strftime);
use Date::Calc qw(Day_of_Week Gmtime Add_Delta_Days Add_Delta_DHMS);
use Sys::Hostname;

@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT = qw();
@EXPORT_OK = qw($_openssl);
$VERSION = '0.40';


# Preloaded methods go here.

# Autoload methods go after =cut, and are processed by the autosplit program.

$CSP::_openssl='openssl';

. . .

$CSP::_openssl='openssl';
. . .
sub genkey
  
    my $self = shift;
    my $args = shift;

    $self->die("Required parameter keyfile missing")
      unless $args->keyfile;

    $args->keysize = 4096 unless $args->keysize > 0;
    $args->keypass = "'" . $self->getPassword("Private key password",1) . "'"
      unless $args->keypass;

    $self->warn("# Password argument: $args->keypass\n") if $ENVCSPDEBUG;

    my $cmd = "-out $args->keyfile $args->keysize";
    $cmd = "-des3 -passout pass:$args->keypass ".$cmd if defined($args->keypass);
    $self->openssl->cmd('genrsa',$cmd,$args);
  

 ## Generate and optionally self-sign the request
  my $process;
  my $what;
  my $common_args = "-$args->digest -days $args->days ".
    " -key $cakey -passin pass:$args->keypass";
  if ($args->csrfile)
    
      $self->openssl->cmd('req',"-new $common_args -out $args->csrfile",$args);
      $what = "generated CA request for";
    
  else
    
      $self->openssl->cmd('req',"-x509 $common_args -new -out $cacert",$args);
      $what = "initialized self-signed";
    

  $self->warn("Successfully $what CA $self->name")
    if $args->verbose;
      
  

sub checkCA
  
    my $self = shift;
    my $dir = $self->caDir();

    $self->die("Uninitialized CA: missing or unreadable ca certificate in $dir")
      unless -r "$dir/ca.crt";

    $self->die("Uninitialized CA: missing or unreadable ca private key in $dir")
      unless -r "$dir/private/ca.key";

    $dir;
  
. . .

在脚本文件的末尾:

. . .
    $self->csp = $csp;

    $cmd = '' if $cmd eq 'dummy';

    my $engine = "-engine opensc" if $ENVCSP_OPENSC;

    my $redirect = ($args->verbose == 0 && $rw ne 'r' ? ">/dev/null 2>&1" : "");
    warn "$lp$self->openssl $cmd $cfgcmd $cmdline $redirect$rp"
      if $ENVCSPDEBUG;
    if ($rw eq 's')
      
  $self->rc = system("$self->openssl $cmd $engine $cfgcmd $cmdline $redirect");
      
    else
      
  open $self->fh,"$lp$self->openssl $cmd $engine $cfgcmd $cmdline $redirect$rp" or
    $self->csp->die("Unable to execute: $!");
      

    $self;
  
. . .

当我使用以下命令行运行它并启用调试时:

csp HLL_ROOT init \
  --keysize=4096 \
  --days=7318 \
  --url=ca.harte-lyne.ca \
  --email=certificates@harte-lyne.ca \
  --digest=sha512 \
  --verbose \
  "CN=HLL_ROOT,OU=Networked Data Services,O=Harte & Lyne Limited,L=Hamilton,ST=Ontario,C=CA,DC=harte-lyne,DC=ca"

然后我看到了:

openssl genrsa  -des3 -passout pass:'a test' -out /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/private/ca.key 4096

接着是:

openssl genrsa  -des3 -passout pass:'a test' -out /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/private/ca.key 4096

并以:

结尾
[CSP][HLL_ROOT] Successfully initialized self-signed CA HLL_ROOT

但是,在上述命令中显示为参数的目录中找不到 ca.key 和 ca.crt 的预期输出。

$ find /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT -name ca\.\*
$ 

但是,如果我将这些确切的命令复制并粘贴到我的 bash 会话 shell 中,它们就可以工作。

openssl genrsa  -des3 -passout pass:'a test' -out /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/private/ca.key 4096
Generating RSA private key, 4096 bit long modulus
.....................................++
........................++
e is 65537 (0x10001)

openssl req  -config /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/tmp/csp-8154.conf  -x509 -sha512 -days 7318  -key /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/private/ca.key -passin pass:'a test' -new -out /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/ca.crt

产量:

$ find /home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT -name ca\.\*
/home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/private/ca.key
/home/byrnejb/Projects/Software/rcsp/ca_test_a/csp/HLL_ROOT/ca.crt

在我看来,命令正在正确创建,但未调用 openssl 实用程序。由于在生成这些命令的部分中没有分支代码,我得出结论认为构造 $self->openssl->cmd('req',"-x509 $common_args -new -out $cacert",$args); 是对 openssl 的实际调用,但我不知道这是如何工作的。

这应该如何工作?为什么它不起作用?

不应该检查openssl的返回码吗?

【问题讨论】:

我们缺少太多代码来回答您的问题。 $self 是对象,$self->openssl 是该对象的属性。它又包含另一个对象,因为它在其上调用方法cmd。请寻找其他出现的$self->openssl,最好是定义它的那个。还包括带有所有userequire 语句的程序顶部。 你是对的,我从一开始就知道。整个脚本可在介绍中给出的公共 github 存储库中找到:github.com/byrnejb/rcsp。我在这里发布的内容已经过长了。 我发现了对我提出的问题的技术正确答案。系统调用位于脚本的末尾,如我刚刚发布的附加代码片段所示。我只是不知道脚本的那部分是如何从创建命令行的位置调用的。这基本上就是我需要向我解释的内容。 我用请求的脚本头信息更新了代码片段。有几十行包含$self->openssl。定义语句是什么样的? 我已经在github上找到了。这是一个 CSP::OpenSSL 对象。该类在同一个文件中定义。在那个 .pm 文件中有几个 packages。 Here 它正在推动某个句柄。那可能是它发出命令的地方。我还在读代码。 【参考方案1】:

根据@simbabque 的评论,openssl 调用的位置在这里:

1398    use IPC::Run qw( start pump finish timeout new_appender new_chunker);
        . . .
1418    sub cmd
1419      
1420        my $self = shift;
1421        my $cmd = shift;
1422        my $cmdline = shift;
1423        my $args = shift;
1424        
1425        my $conf;
1426        my $cfgcmd;
        . . .
1448        $self->_handle->pump while length $$self->_in;
        . . .

潜在的困难是在密码短语中使用嵌入的空格。正如所写的那样,代码将参数作为连接字符串传递给IPC:Run。对于作为字符串传递的参数 IPC:Run 使用空格作为参数分隔符。处理这个问题的正确方法是重构代码以使用数组来传递参数。

【讨论】:

【参考方案2】:

我是那个包的原作者,我早就放弃了它,原因显而易见。去看看https://github.com/leifj/ici 了解一些更易于维护的东西(即使它基本上只是 bash 脚本)

【讨论】:

以上是关于在此脚本中如何以及在何处调用 OpenSSL?的主要内容,如果未能解决你的问题,请参考以下文章

如何以及在何处调用 Database.EnsureCreated 和 Database.Migrate?

如何在 POCO C++ 库中正确使用 OpenSSL

Java 如何处理整数下溢和上溢以及如何检查它?

Java 如何处理整数下溢和上溢以及如何检查它?

如何使用busybox 和openssl 在脚本中更改用户密码?

JIT 编译后如何(以及在​​何处)加载本机代码?