Managing a lot of SSL certificates? Hate being surprised when they expire on you and break your web site? How about a simple process to notify you in advance?

All of the above sound about right? It does to me, I literally manage close to 100 web sites that require SSL encryption for sensitive data transfers, it seems almost impossible to get and keep them all lined up for expiration dates. Even when they were something new would come along and mess up the rotation, in short order it looks like a shotgun blast to a calendar was the deciding factor.

Here is an easy perl script I wrote to check the dates of existing SSL certs, it gets the URL list to check from certs.urls, compares the certificate expiration date to the current date and send emails at the specified intervals. Pretty simple, but like most, it's very effective when run daily via cron.

I've edited some of the partially confidential stuff out, but not enough to render the script unusable by any means, just set the email.sr to your local email faciltiy.

CODE:
  1. #! /usr/local/bin/perl
  2. #
  3. # check_ssl_expire.pl, v 0.01
  4. #
  5. # Inital version - Dave Cochran 9/13/07
  6. ###########################################################
  7. use Switch;
  8. use Time::Local;
  9.  
  10. unshift(@INC, "/pshome/psmgr/bin");
  11. unshift(@INC, "/pshome/psmgr/bin.test") if ("/pshome/psmgr/bin.test" eq "$ENV{'PWD'}");
  12. unshift(@INC, "/pshome/psmgr/stat/bin") if ("/pshome/psmgr/stat/bin" eq "$ENV{'PWD'}");
  13. require sr;
  14.  
  15. $debug = 0;
  16. $debug = 1 if ("/pshome/psmgr/bin.test" eq "$ENV{'PWD'}");
  17. $debug = 1 if ("/pshome/psmgr/stat/bin" eq "$ENV{'PWD'}");
  18. $execute = 1;
  19.  
  20. $path = "/pshome/tmp";
  21. @urls = `cat /pshome/psmgr/files/cert.urls`;
  22.  
  23. foreach $url (@urls) { # start for each url
  24.   chomp $url;
  25.   print "\nChecking $url\n";
  26.   $cmd = "echo \"\" | openssl s_client -connect $url:443> $path/certificate";
  27.   print "\n\n    $cmd\n\n" if ($debug);
  28.   system ($cmd) if ($execute);
  29.  
  30.   $cmd = "openssl x509 -in $path/certificate -noout -enddate> $path/outdate";
  31.   print "    $cmd\n\n" if ($debug);
  32.   system ($cmd)> $result if ($execute);
  33.  
  34.   open (OUTDATE, "/pshome/tmp/outdate")  || die "couldn't open the file!";
  35.   $enddate = <outdate>;
  36.   chomp $enddate;
  37.   close(OUTDATE);
  38.   print "SSL enddate is: <$enddate>\n" if ($debug);
  39.   $expire = substr($enddate, 9, 20);
  40.   print "Expire date : <$expire>\n" if ($debug);
  41.   $month = substr($expire, 0, 3);
  42.   $day = substr($expire, 4, 2);
  43.   $year = substr($expire, 16, 4);
  44.  
  45.   switch ("$month")
  46.   {
  47.     case "Jan"  { $month = 0 }
  48.     case "Feb"  { $month = 1 }
  49.     case "Mar"  { $month = 2 }
  50.     case "Apr"  { $month = 3 }
  51.     case "May"  { $month = 4 }
  52.     case "Jun"  { $month = 5 }
  53.     case "Jul"  { $month = 6 }
  54.     case "Aug"  { $month = 7 }
  55.     case "Sep"  { $month = 8 }
  56.     case "Oct"  { $month = 9 }
  57.     case "Nov"  { $month = 10 }
  58.     case "Dec"  { $month = 11 }
  59.     else        { print "$month is not a valid month. You have problems!\n" }
  60.   } # end switch on month
  61.   $day =~ s/ /0/;
  62.   $expire_date = timegm(1,0,0,$day,$month,$year - 1900);
  63.   $today = `date +%Y%m%d`;
  64.   chomp $today;
  65.   $today = timegm(1,0,0,`date +%d`,`date +%m` -1,`date +%Y` - 1900);
  66.   $thirty_days = $today + (86400 * 30);
  67.   $fifteen_days = $today + (86400 * 15);
  68.   $seven_days = $today + (86400 * 7);
  69.   $one_day = ($today + 86400);
  70.  
  71.   print "Today is <$today> and the cert expires on <$expire_date>\n" if ($debug);
  72.   print "1 day is <$one_day>\n" if ($debug);
  73.   print "7 days is <$seven_days>\n" if ($debug);
  74.   print "15 days is <$fifteen_days>\n" if ($debug);
  75.   print "30 days is <$thirty_days>\n" if ($debug);
  76.  
  77.   $subject = "$url certificate expiration";
  78.   if ($today> $expire_date) { # start if the certificate is expired
  79.     &sr::send_page($debug,"$url cert expired",'Paul Hofmann','David Cochran');
  80.     $message = "The $url certificate is expired";
  81.     print "\t$message\n";
  82.     &sr::send_email($debug,$subject,$message,'David Cochran');
  83.   } # end if the certificate is expired
  84.   elsif ($one_day == $expire_date) { # start else if the certificate will expire in 1 day
  85.     &sr::send_page($debug,"$url cert expires in 1 day",'David Cochran');
  86.     $message = "The $url certificate will expire in 1 day";
  87.     print "\t$message\n";
  88.     &sr::send_email($debug,$subject,$message,'David Cochran');
  89.   } # end if the certificate will expire in 1 day
  90.   elsif ($seven_days == $expire_date) { # start else if the certificate will expire in 7 days
  91.     $message = "The $url certificate will expire in 7 days";
  92.     print "\t$message\n";
  93.     &sr::send_email($debug,$subject,$message,'David Cochran');
  94.   } # end if the certificate will expire in 7 days
  95.   elsif ($fifteen_days == $expire_date) { # start else if the certificate will expire in 15 days
  96.     $message = "The $url certificate will expire in 15 days";
  97.     print "\t$message\n";
  98.     &sr::send_email($debug,$subject,$message,'David Cochran');
  99.   } # end if the certificate will expire in 15 days
  100.   elsif ($thirty_days == $expire_date) { # start else if the certificate will expire in 30 days
  101.     $message = "The $url certificate will expire in 30 days";
  102.     print "\t$message\n";
  103.     &sr::send_email($debug,$subject,$message,'David Cochran');
  104.   } # end if the certificate will expire in 30 days
  105. } # end for each url

URLs are stored in cert.urls with no http:// prefix

CODE:
  1. blog.captivereefing.com
  2. www.captivereefing.com

You get the idea...

Happy hacking!