File Coverage

blib/lib/Net/ACME/Certificate.pm
Criterion Covered Total %
statement 44 46 95.6
branch 6 12 50.0
condition 2 3 66.6
subroutine 10 10 100.0
pod 0 3 0.0
total 62 74 83.7


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 7     7   123481 use strict;
  7         21  
  7         205  
33 7     7   34 use warnings;
  7         11  
  7         201  
34              
35 7     7   471 use Call::Context ();
  7         395  
  7         106  
36 7     7   30 use Crypt::Format ();
  7         12  
  7         106  
37              
38 7     7   460 use Net::ACME::HTTP ();
  7         14  
  7         2890  
39              
40             sub new {
41 4     4 0 2206 my ( $class, %opts ) = @_;
42              
43 4 50       18 die 'requires “content”!' if !$opts{'content'};
44 4 50       15 die 'requires “type”!' if !$opts{'type'};
45 4 50       14 die 'requires “issuer_cert_uri”!' if !$opts{'issuer_cert_uri'};
46              
47 4         12 my $self = bless {}, $class;
48              
49 4         63 $self->{"_$_"} = $opts{$_} for qw(content type issuer_cert_uri);
50              
51 4         24 return $self;
52             }
53              
54             sub issuers_pem {
55 2     2 0 2071 my ($self) = @_;
56              
57 2         11 Call::Context::must_be_list();
58              
59 2         40 my @pems;
60              
61 2         7 my $uri = $self->{'_issuer_cert_uri'};
62 2         8 while ($uri) {
63 3         44 my $http = Net::ACME::HTTP->new();
64 3         12 my $resp = $http->get($uri);
65              
66             #TODO: Check response status code.
67              
68 3         620 _STATIC_die_if_wrong_mime_type( $resp->header('content-type') );
69              
70 3         76 push @pems, _STATIC_der_to_pem( $resp->content() );
71              
72 3         138 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 3 50 66     18 undef $new_uri if $new_uri && $new_uri eq $uri;
77              
78 3         16 $uri = $new_uri;
79             }
80              
81 2         47 return @pems;
82             }
83              
84             sub pem {
85 2     2 0 26 my ($self) = @_;
86              
87 2 50       8 if ( defined $self->{'_type'} ) {
88 2         10 _STATIC_die_if_wrong_mime_type( $self->{'_type'} );
89              
90 2         9 return _STATIC_der_to_pem( $self->{'_content'} );
91             }
92              
93 0         0 return undef;
94             }
95              
96             #----------------------------------------------------------------------
97              
98             sub _STATIC_die_if_wrong_mime_type {
99 5     5   38 my ($type) = @_;
100              
101 5 50       18 if ( $type ne 'application/pkix-cert' ) {
102 0         0 die "Unrecognized certificate MIME type: “$type”";
103             }
104              
105 5         9 return;
106             }
107              
108             sub _STATIC_der_to_pem {
109 5     5   23 my ($der) = @_;
110              
111 5         66 return Crypt::Format::der2pem( $der, 'CERTIFICATE' );
112             }
113              
114             1;