Signing perl script with cert

It is unclear how I need to deal with certs and perl scripts.  I have created a script that downloads files from our site.  My intention is to distribute this script to a few collaborators.  The script needs to connect to our database so they can get certain information as well as do the file download.  But when I do this, I get an error message like this:

500 Can't connect to xyz.com:443 (certificate verify failed) at lwp3.pl line 154

So I believe I need to sign the script with a cert.  From previous experience working with Java, we have signed our jar files and these were distributed.  But with perl, it's a script so how do I "sign" a script and will I need to distribute a cert along with the script?  Users will be running this from their remote machines.
mock5cAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MazdajaiCommented:
Are you trying to download from a website with a self signed cert? This appears to be site issue,  not your script.  Try turn off hostname vertification and post your code.
0
mock5cAuthor Commented:
The script is intended to run from command line by user.  The url(s) that is passed in by the script calls a php script which zips up a bunch of files on the server to create the zip file for downloading.  That is all server side processing that I don't touch.  Multiple urls can be passed in (via query) and this will result in multiple zip files for downloading, which is exactly what I want.  This script is for sending the urls and downloading the zip files.  the lwp connection happens in downloadScan so I am wondering if there are additional settings that must be included with a cert.

#!/usr/bin/perl

use strict;use warnings;
use LWP;
use LWP::UserAgent;
use Getopt::Long qw(:config bundling permute);
use DBI;
use Term::ReadKey;
use Tie::IxHash;

my $platform = "Pg";
my $database = "somedb";
my $host = "some.host";
my $port = "5432";

my $help = 0;
my $inputfile = '';
my $list = 1;
my $num = -1;
my $input = '';

print "Username: ";
ReadMode 'normal';
my $usr = ReadLine 0;
chomp($usr);

print "Password: ";
ReadMode 'noecho';
my $pwd = ReadLine 0;
chomp($pwd);
ReadMode 'normal';
print "\n";

my $dbh = DBI->connect("dbi:$platform:dbname=$database;host=$host;port=$port;" .  "", "$usr", "$pwd", {
               RaiseError => 1,
               PrintError => 1,
               AutoCommit => 0
          });

GetOptions(
   'n|num=i' => \$num,
   'i|input=s' =>\$input
);

my $out;

downloadScans($input);

sub downloadScans{
   my ($opt_value) = @_;

   open(DLIN, "downloadedlist.txt") or warn("downloadedlist.txt does not exist: $!.  File will be created.\n");
   tie my %downloadedlist, 'Tie::IxHash';
   if(-e "downloadedlist.txt"){
      while(my $line = <DLIN>){
         chomp($line);
         my $comment = 0;
         if($line =~ /^#/){
            $line = substr($line,1);
            $comment = 1;
         }
         my ($fname,$url) = split(/\|/,$line);
         $downloadedlist{$fname} = [ "$url", $comment ];
      }
      close(DLIN);
   }

   my @urls;
   my $sQuery = qq(select fname,url from temp.$opt_value;);
   my $aref = $dbh->selectall_arrayref($sQuery);
   @urls = @$aref;

   for my $i(reverse 0 .. $#urls){
      my $fname = $urls[$i][0].".zip";
      my $url = $urls[$i][1];
      # Remove uncommented entries found in downloadedlist
      if(keys(%downloadedlist) > 0){
         if(exists $downloadedlist{$fname} and $downloadedlist{$fname}[1] == 0){
            splice(@urls, $i, 1)
         }
      }
      # Add existing files downloadedlist
      if(-e $fname && ! -z $fname){
         $downloadedlist{$fname} = [ "$url", 0 ];
      }
   }

   $num = (($num >= 0 and $num < scalar(@urls)) ? $num : scalar(@urls));
   print "Downloading $num out of " . scalar(@urls) . " files.\n";
   for(my $i=0; $i < $num;$i++){
      my ($fname,$url) = @{$urls[$i]};

      print "Downloading file $fname.zip ... ";
      # Don't download files that already exist in the directory
      if(-e $fname.".zip" and ! -z $fname.".zip"){
         $downloadedlist{$fname.".zip"} = [ "$url", 0 ];
         print "already downloaded\n";
         next;
      }
      downloadScan($urls[$i]);
      if(-e $fname.".zip" and ! -z $fname.".zip"){
         $downloadedlist{$fname.".zip"} = [ "$url", 0 ];
      }
   }
   open(DLOUT, "+>", "downloadedlist.txt");
   foreach my $fname(keys %downloadedlist){
      my ($url,$comment) = @{$downloadedlist{$fname}};
      print DLOUT ($comment ? "#" : "") . "$fname|$url\n";
   }
   close(DLOUT);
}

sub downloadScan{

   my ($scan) = @_;
   my ($fname,$url) = @$scan;
   $fname =~ s/\s/\_/g;

   my $ua = LWP::UserAgent->new();
   #$ua->timeout(10);
   $ua->env_proxy;
   #$ua->ssl_opts(verify_hostnames => 0);
   $ua->agent("USER/AGENT/INDENTIFICATION");

   my $h = new HTTP::Headers(Content_Base => $url);
   $h->authorization_basic("$usr","$pwd");

   my $request = HTTP::Request->new('GET',$url,$h);
   open($out, '>:raw', $fname.".zip") or die("Unable to open: $!\n");
   my $response = $ua->request($request, \&callback,1024**3);
   #my $response = $ua->get($url);
   close($out);

   if ($response->is_success){
      print "done\n";
   }
   else{
      die $response->status_line;
    }
}

sub callback{
   my ($data, $response, $protocol) = @_;
   print $out $data;
}                                                                                                                                 

Open in new window

0
MazdajaiCommented:
Try un-comment line 122.

Where is line 154?
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
PMI ACP® Project Management

Prepare for the PMI Agile Certified Practitioner (PMI-ACP)® exam, which formally recognizes your knowledge of agile principles and your skill with agile techniques.

mock5cAuthor Commented:
Sorry, I ended up stripping a bunch of stuff out of unnecessary stuff from the script so it has fewer lines.  I ran the script I posted and I get the same error (line 138)

500 Can't connect to xyz.com:443 (certificate verify failed) at lwp3.pl line 138

I get the same error message with line 122 commented or uncommented.

Am I supposed to do anything specific with a cert?
0
MazdajaiCommented:
No you should not have to.

Have you test your script with a site that is http, not https?
0
mock5cAuthor Commented:
I haven't tried without https as that is required.  The script does work in linux, though I'm not sure if it would work on a linux box other than the one I'm running it from, which is the same server that hosts the php scripts.  The issue I'm having seems to be on Windows.  I just tried turning off my firewall in windows but I ended up with same 500 error.
0
MazdajaiCommented:
If it is working in Linux, are you running the same perl version in Windows? Are you able to download the file with a browser in Windows?

Add  use diagnostics; in your code and post the standard error.
0
mock5cAuthor Commented:
use diagnostics did not provide any additional error messages.

I looked at apache logs and here is what I see:


[Mon Sep 09 07:17:42 2013] [info] [client 10.48.45.80] Connection to child 6 established (server xyz.com:443)
[Mon Sep 09 07:17:42 2013] [info] Seeding PRNG with 656 bytes of entropy
[Mon Sep 09 07:17:42 2013] [info] [client 10.48.45.80] SSL library error 1 in handshake (server xyz.com:443)
[Mon Sep 09 07:17:42 2013] [info] SSL Library Error: 336151576 error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
[Mon Sep 09 07:17:42 2013] [info] [client 10.48.45.80] Connection closed to child 6 with abortive shutdown (server xyz.com:443)

Does that offer any clues?
0
MazdajaiCommented:
SSL3_READ_BYTE means the client 10.48.45.80 has problem validating the server certificate.
Typically this can be resolved shutting off hostname verification in ssl option - 'ssl_opts(verify_hostnames => 0)'

What about the following?

Are you running the version of activeperl in Windows?

Open in new window

0
mock5cAuthor Commented:
Yes, I am running activeperl on Windows:

This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x64-multi-thread
(with 1 registered patch, see perl -V for more detail)

I have same failures from another windows machine with an earlier version of activeperl, 5.10 I believe.

ssl_opts(verify_hostnames =>0) has been on and off but still does not work.  Anything else that can be added to skip hostname verification?
0
mock5cAuthor Commented:
Ahh!  I turned out to be a typo on my part.
I had a typo in the ssl_opts.  It should have been singular:
$ua->ssl_opts(verify_hostname => 0);  # not verify_hostnames

Open in new window

I still had warnings on the screen so a google search told me that I needed to add:
use IO::Socket::SSL qw(SSL_VERIFY_NONE)

Open in new window

and then for the ssl_opts use this:
$ua->ssl_opts(
   verify_hostname => 0,
   SSL_verify_mode => SSL_VERIFY_NONE,
);

Open in new window

I would still like to know how to do hostname verification.  It is unclear how to handle certs.  Am I supposed to distribute with the script?  I found a link that suggests that would be the case.
$ua->ssl_opts(
    SSL_ca_file => "$ENV{'HOME'}/ca.pem",
    SSL_cert_file => "$ENV{'HOME'}/my.crt",
    verify_hostname => 1,
);

Open in new window

It appears the cert is saved on the local machine and is referenced by the script.
0
MazdajaiCommented:
I see. I missed the typo in your script as well, line 122.

 #$ua->ssl_opts(verify_hostnames => 0);

Open in new window


Can you first confirm if your script works on the Windows machine now?
0
mock5cAuthor Commented:
Yes, it is working on windows.
0
MazdajaiCommented:
Thank you.

If hostname vertification is turned off (verify_hostname => 0) that you should not need to worry about the certs.

Can you clarify your next question?
0
mock5cAuthor Commented:
Well, my original question was should certs be distributed with the script.  There is a work around by turning off hostname verification.  However, I worry about security issues here so I am trying to determine how to do hostname verification.  Does this involve distributing the cert so that the script can then reference it?
0
MazdajaiCommented:
I recommend avoid cert embedding in your code. If the correct chain of trust is setup correctly on the machine, there is no need to reference it in the script. You mentioned the Linux environment is always working, have you look into why? Is this a self-signed cert on the server?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.