1

I am completely new to Perl. I have written a web service in C# running on a Windows box and am calling it from a Perl script on a Linux box using SOAP::Lite. My code works fine using the http:// handler. I'm now trying to get it to work with https://

The code is:

    use SOAP::Lite;
    use POSIX;

    #Tell Perl to trust the testserver's cert
    #$ENV{HTTPS_CA_DIR} = '/usr/local/share/ca-certificates';
    $ENV{HTTPS_CA_FILE} = '/home/myusername/TestServer_CA_Cert.cer';
    #$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;


    my $uri = 'http://Automation/';
    my $proxy = 'https://TestServer/ToolsAutomation/AutomationInterface.asmx';
    my $method = SOAP::Data->name('SubmitAutomationJob')->attr({xmlns => $uri});

    #-Code that sets us @params deleted for readability-

    my $myServer = SOAP::Lite
        -> on_action(sub {join '', $uri, $_[1]})
        -> proxy($proxy)
    #        -> proxy($proxy, ssl_opts => [ SSL_verify_mode => 0 ] )
    #        -> proxy($proxy, ssl_opts => [SSL_ca_file => $ServerCACert])
            ;

    my $myCALL = $myServer #This is line 36 in the original script
                -> call($method => @params);

    print 'Result: ' . $myCALL->result;

When I run the code as posted, I get error "500 Can't connect to TestServer:443 at line 36." A network trace on the server side shows the client sends a SYN, server sends a SYN/ACK, client sends and ACK, then the client immediately sends a FIN/ACK.

I have tried various things to get this to work. I have tried:

  • Uncommenting the line #$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; results in "500 Can't connect to TestServer:443 (certificate verify failed). Network trace shows that at least part of HTTPS negotiation is working.
  • Uncommenting the line proxy($proxy, ssl_opts => [ SSL_verify_mode => 0 ] ) works, but of course this doesn't verify the server's identity.
  • Uncommenting the line -> proxy($proxy, ssl_opts => [SSL_ca_file => $ServerCACert]) also gives a "certificate verify failed" error.
  • Changing the path to $ENV{HTTPS_CA_FILE} gives an error "SSL_ca_file /home/myusername/TestServer_CA_cert.ceeer does not exist" at the line 36. I take this as a good sign; the code is finding the certificate I tell it to use for server auth.
  • Uncommenting both the $ENV{HTTPS_CA_DIR} and the $ENV{HTTPS_CA_FILE} lines gives the error "only SSL_ca_path or SSL_ca_file should be given."

I have imported my CA's cert into Firefox on the Linux machine and have successfully browsed to my testserver without getting an SSL warning, and then removed the cert from Firefox and browsed back and received the SSL warning, so I'm reasonably confident that the cert file I have is good.

Does anyone have any ideas on how to fix this code? Is there some attribute of the CA's cert itself that I should check? I find it puzzling that Firefox has no problem trusting a server whose SSL cert is signed with this CA's cert, but I can't convince Perl to do the same.

Any feedback is appreciated. And do remember: I'm an absolute Perl n00b. Before I Googled how to call a web service from Perl, the only think I knew about Perl was "Larry Wall."

Thanks!

UPDATE:

At the request of Steffen Ullrich below, I ran the following:

perl -MIO::Socket::SSL=debug4 program.pl

The output I received is:

me@myMachine:~$ perl -MIO::Socket::SSL=debug4 ./program.pl 
DEBUG: .../IO/Socket/SSL.pm:402: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:404: socket connected
DEBUG: .../IO/Socket/SSL.pm:422: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:1388: SSL structure creation failed
Nevo
  • 752
  • 2
  • 9
  • 22
  • Similar question that may help: http://stackoverflow.com/questions/14839098/perl-cannot-access-web-service-with-ssl – Narthring Oct 20 '15 at 14:57

2 Answers2

1

When I run the code as posted, I get error "500 Can't connect to TestServer:443 at line 36." A network trace on the server side shows the client sends a SYN, server sends a SYN/ACK, client sends and ACK, then the client immediately sends a FIN/ACK.

If this is really like you describe it then no data gets exchanged which means th client does not even attempt to do an SSL handshake. This means that probably the way you called it is wrong:

#        -> proxy($proxy, ssl_opts => [ SSL_verify_mode => 0 ] )
#        -> proxy($proxy, ssl_opts => [SSL_ca_file => $ServerCACert])

I'm pretty sure that ssl_opts does not need an array ([...]) but a hash ({...}).

EDIT: It looks like you need an array and not a hash because ssl_opts are handled in a special way by SOAP::Lite, i.e. they are not directly given to the constructor of LWP::UserAgent as the documentation would imply. I've filed a bug about it.

DEBUG: .../IO/Socket/SSL.pm:1388: SSL structure creation failed

Based on the code I got from you I could reproduce the problem, but only if the given CA file was corrupt. I expect that this is the case for you. Note that the file must look like this:

-----BEGIN CERTIFICATE-----
MIIDKDCCApGgAwIBAgIJAOetiwdVihcnMA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNV
.... more base64 encoded stuff ...
M0LUhtV8z6OcURDEfnQBsgLCPODc9Mg4FEViDGVaZ1i233ZeAlLzXSZeXL8=
-----END CERTIFICATE-----
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • You're right; in that one test case, the handshake doesn't get attempted. In the other test cases, the handshake does complete enough for the client to return a 'certificate verify failed' error. In addition, when I use the first commented line that you quoted, the client does successfully connect to the server, but of course doesn't do certificate validation checks. – Nevo Oct 20 '15 at 18:12
  • @Nevo: could you please call your code with the correct SSL_ca_file and additionally with `perl -MIO::Socket::SSL=debug4 program.pl` and add the debug output to your question? – Steffen Ullrich Oct 20 '15 at 19:47
  • Steffen, see the update to the original post. Thank you for that. I'm researching the output of the debug command now. – Nevo Oct 20 '15 at 20:16
  • `SSL structure creation failed` is really strange. Can you please make sure that the code you have published *exactly* reflects what you use for testing, that you `use strict;` and `use warnings;` and that you use ssl_opts with a hash and not an array as in your code example. – Steffen Ullrich Oct 20 '15 at 20:34
  • Steffen, I added use strict; and use warnings; and verified that my code is accurately reflected in what I posted. I'm not using any ssl_opts in my default test case.I uncommented the proxy line that specifies the SSL_ca_file and put it in curly braces instead of square brackets and the issue is the same. Uncommenting the line that specifies SSL_verify_mode=>0 works when the ssl_opts is in square brackets but I get the same SSL structure creation failed when I put it in curly braces. – Nevo Oct 21 '15 at 16:16
  • @Nevo: It is still really strange for me what happens, especially that for you an array with `ssl_opts` works while an hash(`{}`) not. What I see from the code in SOAP::Lite and LWP it says that it should croak when `ssl_opts` is used with an array (`[]`). I suggest that you make sure that all of the packages you use are recent and please document the versions you use. Also, if I could reproduce the problem I might help you but for this I need the full example, not only the parts from it you consider relevant for the question. – Steffen Ullrich Oct 21 '15 at 17:53
  • I installed Eclipse and EPIC and found that the error is happening at line 430 in SSL.pm version 1.965. This is a call to Net::SSLeay::new. When I single-step in the debugger, I'm immediately taken to sub error on line 1386 of SSL.pm. I expected to be stepped into Net::SSLeay::new. I don't understand enough about Perl to know why I was taken to sub error instead of into the SSLeay code. If I could get the debugger to step into SSLeay I might be able to provide more clues, or even figure this out for myself. – Nevo Oct 22 '15 at 15:10
  • @Nevo: I think your problem is a CA file in the wrong format. See edited response. – Steffen Ullrich Oct 22 '15 at 16:26
1

Steffen provided the correct solution to the problem. When I originally exported the CA cert from the Windows CA, I exported it in "DER encoded binary X.509" format. This is what failed.

I re-exported the certificate in "Base-64 encoded X.509" format and used that in my Perl script and now things are working properly.

Nevo
  • 752
  • 2
  • 9
  • 22