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