8

我正在将应用程序从 PHP/cURL 移植到 Perl 和 LWP::UserAgent。我需要向 Web 服务器发出 POST 请求并提供客户端证书和密钥文件。我试图复制的 PHP 代码是这样的:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
curl_setopt($ch, CURLOPT_SSLCERT, "/path/to/certificate.pem"); 
curl_setopt($ch, CURLOPT_SSLKEY, "/path/to/private.key"); 
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, "secretpassword");

这是我的 Perl 代码:

my $ua = LWP::UserAgent->new();
$ua->ssl_opts(
   SSL_verify_mode => 0,
   SSL_cert_file   => '/path/to/certificate.pem',
   SSL_key_file    => "/path/to/private.key",
   SSL_passwd_cb   => sub { return "secretpassword"; }  
);

PHP 代码成功连接到服务器,但 Perl 代码失败:

SSL 读取错误错误:14094410:SSL 例程:SSL3_READ_BYTES:sslv3 警报握手失败

我无法弄清楚我错过了什么。

4

3 回答 3

2

上面emazep的回答解决了我的问题。我正在使用来自 UPS 的示例 Perl 代码通过 XML 连接到他们的 Rate 服务。根据我的测试,这将在任何时候调用 LWP::UserAgent 而不使用您可以直接控制的参数,如果您使用其他一些为您调用 LWP 的模块,这将很方便。只需使用 Net::SSL(除了已经使用 LWP 的任何包)并设置一些环境变量:

...
use Net::SSL;
$ENV{HTTPS_VERSION} = 3;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
my $browser = LWP::UserAgent->new();
...

而已!您甚至不需要使用 $ENV{PERL_LWP_SSL_CA_FILE} 指定服务器根证书的路径。

于 2012-11-13T17:02:12.583 回答
2
sub send_command(){
        my $command = shift;
        my $parser = XML::LibXML->new('1.0','utf-8');

        print color ("on_yellow"), "SEND: ", $command, color ("reset"), "\n";

        # Create a request
        my $req = HTTP::Request->new( GET => $Gateway.$command );

        # Pass request to the user agent and get a response back
        my $res;
        eval {
                 my $ua;
                 local $SIG{'__DIE__'};
                 $ua = LWP::UserAgent->new(); #  или 
                 $ua->ssl_opts( #$key => $value 
                    SSL_version         => 'SSLv3',
                    SSL_ca_file         => '/ca.pem',
                    #SSL_passwd_cb       => sub { return "xxxxx\n"; },
                    SSL_cert_file       => '/test_test_cert.pem',
                    SSL_key_file        => '/test_privkey_nopassword.pem',
                ); # ssl_opts => { verify_hostname => 0 }
                 $ua->agent("xxxxxx xxxx_tester.pl/0.1 ");
                 $res = $ua->request($req);

        };  
        warn $@ if $@;
        # Check the outcome of the response
        if ( $res->is_success ) {
                open  xxxLOG, ">> $dir/XXXX_tester.log";
                my $without_lf = $res->content;
                $without_lf =~ s/(\r|\n)//gm;
                print PAYLOG $without_lf,"\n";
                close PAYLOG;
        }
        else {
                 return $res->status_line;
        }       
        print  color ("on_blue"), "RESPONSE: ", color ("reset"), respcode_color($res->content), color ("reset"),"\n\n";
        return $res->content;
} 
于 2012-10-12T12:45:35.293 回答
1

确实,这有点混乱。根据您的设置,LWP::UserAgent 可能使用(至少)两个 SSL 模块之一来处理 SSL 连接。

  • IO::Socket::SSL
  • 网络::SSL

第一个应该是较新版本的 LWP::UserAgent 的默认值。您可以通过在终端中为每个模块运行标准命令来测试安装了哪些:

perl -e 'use <module>;'

IO::socket::SSL 需要带有 ssl_opts 的 SSL 配置,如您的示例所示。

Net::SSL 需要环境变量中的 SSL 配置,如 goddogsrunnings 的答案。

就我个人而言,我属于第二类,并从 Crypt::SSLeay 页面中获得了很好的灵感。特别是名为“客户证书支持”的部分。

于 2015-09-24T12:39:43.597 回答