diff --git a/acme-tinier.pl b/acme-tinier.pl index 5e877a0..c34cce3 100755 --- a/acme-tinier.pl +++ b/acme-tinier.pl @@ -70,8 +70,8 @@ sub send_signed { my $b64payload = b64 $json->encode($payload); my $b64protected = b64 $json->encode($protected); - my $out = communicate('openssl', 'dgst', '-sha256', '-sign', $account_key, - "$b64protected.$b64payload"); + my $out = communicate('openssl', 'dgst', '-sha256', '-sign', + $account_key, "$b64protected.$b64payload"); die 'cannot sign request' if $? >> 8; return get $url, $json->encode({ header => $header, protected => $b64protected, @@ -99,7 +99,32 @@ my ($code, $result, $headers) = get "$ca/terms"; }); die "cannot register: $code" if $code != 201 && $code != 409; -# Run each domain through the ACME challenge +# Check if the file is really there, submit an HTTP challenge and wait +sub verify_http { + my ($checked_url, $key_auth, $challenge_uri) = @_; + my ($code, $result) = get $checked_url; + die "checking $checked_url failed: $code" if $code != 200; + die 'challenge contents differ' if $result ne $key_auth; + + ($code, $result) = send_signed($challenge_uri, { + resource => 'challenge', keyAuthorization => $key_auth + }); + die "challenge submission failed: $code" if $code != 202; + + while (1) { + ($code, $result) = get $challenge_uri; + die "challenge verification failed: $code" if $code >= 400; + my $status = $json->decode($result); + if ($status->{status} eq 'valid') { + last; + } elsif ($status->{status} eq 'pending') { + sleep 1; + } else { + die "challenge verification failed: $result"; + } + } +} + for my $domain (@domains) { my ($code, $result) = send_signed("$ca/acme/new-authz", { resource => 'new-authz', @@ -113,52 +138,24 @@ for my $domain (@domains) { my $key_auth = "$token.$thumbprint"; my $known_path = "$acme_dir/$token"; - # Make the challenge file and check that it can be retrieved - open(my $fh, '>', $known_path) or die "cannot write $known_path: $!"; + open(my $fh, '>', $known_path) or die "cannot write to $known_path: $!"; print $fh $key_auth; close $fh; -eval { - my $url = "http://$domain/.well-known/acme-challenge/$token"; - my ($code, $result) = get $url; - die "checking $url failed: $code" if $code != 200; - die 'challenge contents differ' if $result ne $key_auth; + eval { verify_http("http://$domain/.well-known/acme-challenge/$token", + $key_auth, $challenge->{uri}) }; - # Submit the challenge and wait for the verification to finish - ($code, $result) = send_signed($challenge->{uri}, { - resource => 'challenge', - keyAuthorization => $key_auth - }); - die "challenge submission failed: $code" if $code != 202; - - while (1) { - ($code, $result) = get $challenge->{uri}; - die "challenge verification failed: $code" if $code >= 400; - my $status = $json->decode($result); - if ($status->{status} eq 'valid') { - last; - } elsif ($status->{status} eq 'pending') { - sleep 1; - } else { - die "challenge verification failed: $result"; - } - } -}; - - # Make sure our file gets deleted and rethrow any error unlink $known_path; - die $@ if $@; + die "$domain: $@" if $@; } -# Get the new certificate and print it in the PEM format +# Get the new certificate and convert it to the PEM format my $der = `openssl req -in '$csr_file' -outform DER`; die 'cannot convert CSR' if $?; ($code, $result) = send_signed("$ca/acme/new-cert", { - resource => 'new-cert', - csr => b64 $der + resource => 'new-cert', csr => b64 $der }); die "cannot sign certificate: $code" if $code != 201; -print "-----BEGIN CERTIFICATE-----\n" - . join("\n", unpack '(A64)*', encode_base64($result, '')) - . "\n-----END CERTIFICATE-----\n"; +my $pem = join("\n", unpack '(A64)*', encode_base64($result, '')); +print "-----BEGIN CERTIFICATE-----\n$pem\n-----END CERTIFICATE-----\n";