File Coverage

blib/lib/Net/ACME/Certificate.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Net::ACME::Certificate;
2              
3             =pod
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             Net::ACME::Certificate - resource abstraction for C
10              
11             =head1 SYNOPSIS
12              
13             my $has_cert = Net::ACME::Certificate->new(
14             content => $cert_der,
15             type => 'application/pkix-cert',
16             issuer_cert_uri => 'http://uri/to/issuer/cert',
17             );
18              
19             my $cert_pem2 = $has_cert->pem();
20             my (@issuers_pem) = $has_cert->issuers_pem();
21              
22             =head1 DESCRIPTION
23              
24             This module encapsulates interaction with ACME “certificate” resources
25             when the certificate is available.
26              
27             For handling cases of non-availability (i.e., HTTP 202 status from the
28             ACME server), see C.
29              
30             =cut
31              
32 1     1   54291 use strict;
  1         2  
  1         20  
33 1     1   3 use warnings;
  1         1  
  1         17  
34              
35 1     1   420 use Call::Context ();
  1         180  
  1         13  
36 1     1   3 use Crypt::Format ();
  1         1  
  1         10  
37              
38 1     1   302 use Net::ACME::HTTP ();
  0            
  0            
39              
40             sub new {
41             my ( $class, %opts ) = @_;
42              
43             die 'requires “content”!' if !$opts{'content'};
44             die 'requires “type”!' if !$opts{'type'};
45             die 'requires “issuer_cert_uri”!' if !$opts{'issuer_cert_uri'};
46              
47             my $self = bless {}, $class;
48              
49             $self->{"_$_"} = $opts{$_} for qw(content type issuer_cert_uri);
50              
51             return $self;
52             }
53              
54             sub issuers_pem {
55             my ($self) = @_;
56              
57             Call::Context::must_be_list();
58              
59             my @pems;
60              
61             my $uri = $self->{'_issuer_cert_uri'};
62             while ($uri) {
63             my $http = Net::ACME::HTTP->new();
64             my $resp = $http->get($uri);
65              
66             #TODO: Check response status code.
67              
68             _STATIC_die_if_wrong_mime_type( $resp->header('content-type') );
69              
70             push @pems, _STATIC_der_to_pem( $resp->content() );
71              
72             my $new_uri = { $resp->links() }->{'up'};
73              
74             #Paranoia: Detect weirdness where an ACME server might consider
75             #a root cert to be its own issuer (cuz it is, really).
76             undef $new_uri if $new_uri && $new_uri eq $uri;
77              
78             $uri = $new_uri;
79             }
80              
81             return @pems;
82             }
83              
84             sub pem {
85             my ($self) = @_;
86              
87             if ( defined $self->{'_type'} ) {
88             _STATIC_die_if_wrong_mime_type( $self->{'_type'} );
89              
90             return _STATIC_der_to_pem( $self->{'_content'} );
91             }
92              
93             return undef;
94             }
95              
96             #----------------------------------------------------------------------
97              
98             sub _STATIC_die_if_wrong_mime_type {
99             my ($type) = @_;
100              
101             if ( $type ne 'application/pkix-cert' ) {
102             die "Unrecognized certificate MIME type: “$type”";
103             }
104              
105             return;
106             }
107              
108             sub _STATIC_der_to_pem {
109             my ($der) = @_;
110              
111             return Crypt::Format::der2pem( $der, 'CERTIFICATE' );
112             }
113              
114             1;