2012-10-02 23 views
8

Przekazuję aplikację z PHP/cURL do Perla i LWP :: UserAgent. Muszę wysłać żądanie POST do serwera WWW i dostarczyć certyfikat klienta i plik klucza. Kod PHP Próbuję replikować to:Używanie LWP z SSL i certyfikatami klienta

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"); 

A oto mój kod 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"; } 
); 

kod PHP z powodzeniem łączy się z serwerem, ale kod Perl nie powiedzie się z:

Błąd odczytu protokołu SSL: 14094410: Procedury SSL: SSL3_READ_BYTES: błąd uzgadniania alertu sslv3

Nie mogę ustalić, czego mi brakuje.

+0

Czy 'private.key' (PHP) i' private.pem' (Perl) to literówka lub część portowania? – amon

+2

Przekazywanie wielu argumentów do [ssl_opts] (https://metacpan.org/module/LWP::UserAgent#ATTRIBUTES) nie jest udokumentowane. Aby być bezpiecznym, wywołaj ssl_opts kilka razy lub przekaż je do konstruktora. Myślę, że to działa, ale lepiej bezpieczne. Możesz również [zgłosić to jako błąd/brakującą funkcję] (https://rt.cpan.org/Public/Bug/Report.html?Queue=libwww-perl). – Schwern

+0

To był tylko literówka, kiedy zasłoniłem kod. Powinien to być private.key dla obu. Dzięki za uwagę, ale to nie problem. Nadal potrzebujesz pomocy! :) – kent

Odpowiedz

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 [email protected] if [email protected]; 
     # 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; 
} 
3

Odpowiedź od emazepa powyżej rozwiązała mój problem. Używam przykładowego kodu Perla z UPS, aby połączyć się z ich usługą Rate poprzez XML. Z moich testów będzie to działało za każdym razem, gdy wywoływana jest LWP :: UserAgent bez argumentów, które można kontrolować bezpośrednio, co czyni go przydatnym, jeśli używasz jakiegoś innego modułu, który wykonuje połączenia do LWP. Po prostu użyj Net :: SSL (oprócz pakietów, które już używały LWP) i ustaw kilka zmiennych środowiskowych:

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

To wszystko! Nie musisz nawet określać ścieżki do głównego certyfikatu serwera za pomocą $ ENV {PERL_LWP_SSL_CA_FILE}.

1

Rzeczywiście jest to trochę kłopotliwe. W zależności od konfiguracji LWP :: UserAgent może używać jednego z (co najmniej) dwóch modułów SSL do obsługi połączenia SSL.

  • IO :: Socket :: SSL
  • Net :: SSL

Pierwszy z nich powinien być domyślny dla nowszych wersji LWP :: UserAgent. Można sprawdzić, które z nich są zainstalowane, uruchamiając standardową komendę w terminalu dla każdego modułu:

perl -e 'use <module>;' 

IO :: gniazdo :: SSL wymaga konfiguracji SSL z ssl_opts jak w przykładzie.

Net :: SSL wymaga konfiguracji SSL w zmiennych środowiskowych, jak w odpowiedzi goddogsrunnings.

Osobiście zaliczam się do drugiej kategorii i miałem dobrą inspirację od Crypt::SSLeay page. Szczególnie sekcja o nazwie "WSPARCIE CERTYFIKATU KLIENTA".