From 391d46d192e1c44ade58f2bed117977bc6cbfc2d Mon Sep 17 00:00:00 2001 From: Nigel Kukard Date: Thu, 19 Jan 2017 22:17:42 +0000 Subject: [PATCH] Major code cleanup regarding error handling --- awit-certmaster | 131 ++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 70 deletions(-) diff --git a/awit-certmaster b/awit-certmaster index df4b1bb..dfead85 100755 --- a/awit-certmaster +++ b/awit-certmaster @@ -47,7 +47,7 @@ package AWIT::CertMaster; use strict; use warnings; -our $VERSION = '1.03'; +our $VERSION = '1.04'; BEGIN { @@ -120,7 +120,7 @@ sub accountInit # Check if the dir was created if (! -d $dir) { $self->logger("ERROR","Failed to create directory '%s'",$dir); - exit 1; + return; } # Check if the file exists, if it does, we need to create else login @@ -136,16 +136,14 @@ sub accountInit close($FH); } else { $self->logger("ERROR","Failed to read account key file '%s': %s",$keyFile,$!); - exit 1; + return; } return $self->accountLogin($keyPEM); } # Create an account - $self->accountCreate({ - 'contact' => sprintf('root@%s',hostname()) - }); + $self->accountCreate({ 'contact' => sprintf('root@%s',hostname()) }) or return; # Open keyfile and read it in umask(0177); @@ -155,7 +153,7 @@ sub accountInit close($FH); } else { $self->logger("ERROR","Failed to read account key file '%s': %s",$keyFile,$!); - exit 1; + return; } return $self; @@ -232,7 +230,7 @@ sub webserverCheckApache } else { # Fail if we cannot open the configuration directory $self->logger("ERROR","APACHE: Failed to open configuration directory '%s': %s",$dataDir,$!); - exit 1; + return; } # Loop with config files found @@ -301,7 +299,7 @@ sub webserverCheckApache # Reload Apache - $self->_webserverReloadApache(); + $self->_webserverReloadApache() or return; return $self; } @@ -335,7 +333,7 @@ sub webserverCheckNginx } else { # Fail if we cannot open the configuration directory $self->logger("ERROR","NGINX: Failed to open configuration directory '%s': %s",$dataDir,$!); - exit 1; + return; } # Loop with config files found @@ -398,7 +396,7 @@ sub webserverCheckNginx } # Reload NGINX - $self->_webserverReloadNginx(); + $self->_webserverReloadNginx() or return; return $self; } @@ -600,19 +598,20 @@ SKIP: # If we still have entries, we need to start processing! - $self->accountInit(); + $self->accountInit() or return; # Verify domains foreach my $vhostName (keys %{$vhostConfig}) { my $vhost = $vhostConfig->{$vhostName}; foreach my $domain (keys %{$vhost->{'server_names'}}) { - $self->domainAdd($domain); - $self->domainVerify($domain); + $self->domainAdd($domain) or return; + $self->domainVerify($domain) or return; } # Retrieve certificate my $certs = $self->certificateRetrieve($vhostName); + return if (!$certs); $self->logger("INFO","WEBSERVER: Writing certificates"); @@ -857,7 +856,7 @@ sub _parse_x509_datetime # Regex string if ($string !~ /(...) (..) (..):(..):(..) (....) (...)/) { $self->logger("ERROR","CORE: The X509 date provided is invalid '%s'",$string); - exit 1; + return; } # Grab components my ( $b, $d, $H, $M, $S, $Y, $Z ) = ($1, $2, $3, $4, $5, $6, $7); @@ -881,13 +880,13 @@ sub _parse_x509_datetime my $month = $month_by_name->{$b}; if (!defined($month)) { $self->logger("ERROR","CORE: Invalid month in X509 date '%s'",$string); - exit 1; + return; } # Check timezone is right if ($Z ne 'GMT' && $Z ne 'UTC') { $self->logger("ERROR","CORE: Invalid timezone in X509 date '%s'",$string); - exit 1; + return; } # Build DateTime object @@ -935,7 +934,7 @@ use MIME::Base64 qw( -our $VERSION = '1.00'; +our $VERSION = '1.01'; # Take care of created files my @_created_files = (); @@ -1005,28 +1004,28 @@ sub accountCreate # Make sure we have args if (!defined($args)) { $self->logger("ERROR",'LE: createAccount: $args is required'); - exit 1; + return; } if (!exists($args->{'contact'})) { $self->logger("ERROR","LE: createAccount: 'contact' is required"); - exit 1; + return; } # Create RSA key my $key = $self->_createKeyRSA(); # Load key - $self->loadKey($key); + $self->loadKey($key) or return; # Load resource directory - $self->leDirectory(); + $self->leDirectory() or return; # Register account - $self->leRegister('contact' => $args->{'contact'}); + $self->leRegister('contact' => $args->{'contact'}) or return; # Accept TOS - $self->leAcceptTOS(); + $self->leAcceptTOS() or return; $self->{'ready'} = 1; @@ -1042,16 +1041,16 @@ sub accountLogin # Load key - $self->loadKey($key); + $self->loadKey($key) or return; # Load resource directory - $self->leDirectory(); + $self->leDirectory() or return; # Register account - $self->leRegister(); + $self->leRegister() or return; # Accept TOS - $self->leAcceptTOS(); + $self->leAcceptTOS() or return; $self->{'ready'} = 1; @@ -1069,7 +1068,7 @@ sub domainAdd # Check that we're ready if (!$self->{'ready'}) { $self->logger("ERROR","LE: A call to accountLogin/Create must be made before domainAdd()"); - exit 1; + return; } return $self->leAuthz($domain); @@ -1086,10 +1085,10 @@ sub domainVerify # Check that we're ready if (!$self->{'ready'}) { $self->logger("ERROR","LE: A call to accountLogin/Create must be made before domainVerify()"); - exit 1; + return; } - $self->leHandleChallenge($domain); + $self->leHandleChallenge($domain) or return; push(@{$self->{'domains_verified'}},$domain); @@ -1107,7 +1106,7 @@ sub certificateRetrieve # Check that we're ready if (!$self->{'ready'}) { $self->logger("ERROR","LE: A call to accountLogin/Create must be made before certificateCSR()"); - exit 1; + return; } $self->logger("INFO","LE: Generating CSR"); @@ -1126,7 +1125,7 @@ sub certificateRetrieve my $rsa = Crypt::OpenSSL::RSA->new_private_key($certKeyPEM); if (!$rsa) { $self->logger("ERROR","LE: certificateRetrieve: Failed to load certificate key into OpenSSL"); - exit 1; + return; } # Padding for PKCS10 @@ -1162,6 +1161,7 @@ sub certificateRetrieve # Convert CSR PEM into DER my $csrDER = $self->_pem_to_der($csrPEM); + return if (!$csrDER); # Build the request we are about to send my $json = $self->_encode_json({ @@ -1176,24 +1176,24 @@ sub certificateRetrieve # And post it... my $resp = $self->_leRequestPost($self->{'directory'}->{'new-cert'}, $jws); - # Make sure result code is right if ($resp->code() != 201) { $self->logger("ERROR","LE: An invalid response was received from resource 'new-cert': %s",$resp->content()); - exit 1; + return; } # Grab certificate DER my $certDER = $resp->content(); + return if (!$certDER); # Grab resources from header my $resources = {}; - $self->_leDirectoryLinks($resources,$resp->header('link')); + $self->_leDirectoryLinks($resources,$resp->header('link')) or return; # Make sure we got a chain URL if (!defined($resources->{'up'})) { $self->logger("ERROR","LE: No certificate chain was received",$resp->content()); - exit 1; + return; } # Pull out the chain @@ -1205,7 +1205,7 @@ sub certificateRetrieve $resp = $self->{'user_agent'}->get($certChainURL); if ($resp->code() != 200) { $self->logger("ERROR","LE: An invalid response was received from resource 'up', certificate chain URL: %s",$resp->content()); - exit 1; + return; } # Grab the certificate chain in DER format @@ -1243,10 +1243,9 @@ sub loadKey my $rsa = Crypt::OpenSSL::RSA->new_private_key($key); if (!$rsa) { $self->logger("ERROR","LE: loadKey: Failed to load key into OpenSSL"); - exit 1; + return; } - # Use SHA256 hashing $rsa->use_sha256_hash(); @@ -1272,11 +1271,10 @@ sub leDirectory # Make a request for the server directory my $resp = $self->_leRequestGet( $self->{'server'} ); - # Make sure we got a success if ($resp->code() != 200) { $self->logger("ERROR","LE: Failed to fetch the server resource direcotry '%s': %s",$self->{'server'},$resp->status_line()); - exit 1; + return; } # Decode the directory response @@ -1313,12 +1311,8 @@ sub leRegister # Do the actual post... my $resp = $self->_leRequestPost($self->{'directory'}->{'new-reg'}, $jws); - - # Grab response code - my $respCode = $resp->code(); - # Error code 409 means 'already registered' - if ($respCode == 409) { + if ($resp->code() == 409) { $self->logger("NOTICE","LE: Known key used, refetching with 'reg' resource"); @@ -1332,10 +1326,10 @@ sub leRegister # Check result if ($resp->code() != 202) { $self->logger("ERROR","LE: Problem when refetching with 'reg' resource: %s",$resp->content()); - exit 1; + return; } - $self->_leDirectoryLinks($self->{'directory'},$resp->header('link')); + $self->_leDirectoryLinks($self->{'directory'},$resp->header('link')) or return; # Error code 201 is a success } elsif ($resp->code() == 201) { @@ -1343,12 +1337,12 @@ sub leRegister # Save 'reg' resource $self->{'directory'}->{'reg'} = $resp->header('location'); - $self->_leDirectoryLinks($self->{'directory'},$resp->header('link')); + $self->_leDirectoryLinks($self->{'directory'},$resp->header('link')) or return; # Any other code is a problem } else { $self->logger("ERROR","LE: Problem when refetching with 'reg' resource: %s",$resp->content()); - exit 1; + return; } return $self; @@ -1384,11 +1378,10 @@ sub leAcceptTOS my $jws = $self->_leCreateJWS($json); my $resp = $self->_leRequestPost($self->{'directory'}->{'reg'}, $jws); - # Check if we got a success code back if ($resp->code() != 202) { $self->logger("ERROR",'LE: Failed to accept TOS: %s',$resp->content()); - exit 1; + return; } # Remove 'reg' resource @@ -1408,7 +1401,7 @@ sub leAuthz # Make sure that our next resource is present if (!exists($self->{'directory'}->{'next'})) { $self->logger("ERROR","LE: Resource 'next' does not exist"); - exit 1; + return; } $self->logger("INFO","LE: Authorizing domain '%s'",$domain); @@ -1424,11 +1417,10 @@ sub leAuthz my $jws = $self->_leCreateJWS($json); my $resp = $self->_leRequestPost($self->{'directory'}->{'next'}, $jws); - # Check if we got a positive response back or not if ($resp->code() != 201) { $self->logger("ERROR","LE: Error with resource 'new-authz': %s",$resp->content()); - exit 1; + return; } # Grab the JSON reply @@ -1440,7 +1432,7 @@ sub leAuthz # Make sure we actually got challenges back if (!exists($jsonRef->{'challenges'})) { $self->logger("ERROR","LE: Error with resource 'new-authz': %s",$resp->content()); - exit 1; + return; } # Load challenges into ourself for this domain @@ -1461,7 +1453,7 @@ sub leHandleChallenge # Check challenge exists if (!exists($self->{'challenges'}->{$domain})) { $self->logger("ERROR","LE: Challenges for domain '%s' does not exist",$domain); - exit 1; + return; } # Check if any of the challenges were already validated @@ -1539,19 +1531,19 @@ sub leHandleChallenge # If there was no http-01 challenge, then its an error if (!defined($challenge)) { $self->logger("ERROR","LE: No 'http-01' challenge was received for domain '%s'",$domain); - exit 1; + return; } # Check we have a 'token' if (!defined($challenge->{'token'})) { $self->logger("ERROR","LE: The 'http-01' challenge for domain '%s' does not contain 'token'",$domain); - exit 1; + return; } # Check we have a 'uri' if (!defined($challenge->{'uri'})) { $self->logger("ERROR","LE: The 'http-01' challenge for domain '%s' does not contain 'uri'",$domain); - exit 1; + return; } @@ -1567,7 +1559,7 @@ sub leHandleChallenge # Check if the dir was created if (! -d $dir) { $self->logger("ERROR","LE: Failed to create directory '%s'",$dir); - exit 1; + return; } # Create file... @@ -1580,7 +1572,7 @@ sub leHandleChallenge # If the open failed, ERR out } else { $self->logger("ERROR","LE: Failed to create file '%s': %s",$dir,$!); - exit 1; + return; } # Add file to get cleaned up @@ -1602,12 +1594,11 @@ sub leHandleChallenge my $jws = $self->_leCreateJWS($json); my $resp = $self->_leRequestPost($challenge->{'uri'}, $jws); - # Make sure if we got the wrong code we abort if ($resp->code() != 202) { $self->logger("ERROR","LE: Wrong response code received from the resource 'challenge' for domain '%s': %s", $domain,$resp->content()); - exit 1; + return; } # Grab the JSON reply @@ -1620,6 +1611,7 @@ sub leHandleChallenge if (!exists($jsonRef->{'uri'})) { $self->logger("ERROR","LE: There appears to be a problem with the resource 'challenge' response for domain '%s': %s", $domain,$json); + return; } # Grab the status URI @@ -1636,12 +1628,11 @@ sub leHandleChallenge sleep(2); $resp = $self->_leRequestGet($statusURI); - # Make sure if we got the wrong code we abort if ($resp->code() != 202) { $self->logger("ERROR","LE: Wrong response code received from the challenge status check for domain '%s': %s", $domain,$resp->content()); - exit 1; + return; } # Grab the JSON reply @@ -1658,12 +1649,12 @@ sub leHandleChallenge # If something is invalid, error out } elsif ($jsonRef->{'status'} eq "invalid") { $self->logger("ERROR","LE: There appears to be a problem with the status response for domain '%s': %s",$domain,$json); - exit 1; + return; # Anything else is known } else { $self->logger("ERROR","LE: Unknown status response: %s",$json); - exit 1; + return; } $self->logger("INFO","LE: - Waiting for verification"); @@ -1785,7 +1776,7 @@ use Getopt::Long; my $NAME = "AWIT-CertMaster"; -our $VERSION = "1.1.5"; +our $VERSION = "1.1.6"; -- GitLab