File Coverage

blib/lib/Crypt/RSA/Parse/Parser.pm
Criterion Covered Total %
statement 64 66 96.9
branch 4 6 66.6
condition 6 12 50.0
subroutine 21 21 100.0
pod 0 5 0.0
total 95 110 86.3


line stmt bran cond sub pod time code
1             package Crypt::RSA::Parse::Parser;
2              
3 2     2   1593 use Crypt::RSA::Parse::Convert_ASN1 ();
  2         7  
  2         42  
4 2     2   1048 use Crypt::RSA::Parse::KeyBase ();
  2         19  
  2         46  
5 2     2   1055 use Crypt::RSA::Parse::Private ();
  2         4  
  2         58  
6 2     2   969 use Crypt::RSA::Parse::Public ();
  2         5  
  2         40  
7 2     2   1108 use Crypt::RSA::Parse::Template ();
  2         8  
  2         2067  
8              
9             our $_BASE64_MODULE;
10             *_BASE64_MODULE = \$Crypt::RSA::Parse::BASE64_MODULE;
11              
12             sub new {
13 1     1 0 2 my ($class) = @_;
14              
15 1         24 my $asn1 = Crypt::RSA::Parse::Convert_ASN1->new();
16 1         40 $asn1->prepare_or_die( Crypt::RSA::Parse::Template::get_template($class->_TEMPLATE_TYPE()) );
17              
18 1         18 return bless { _asn1 => $asn1 }, $class;
19             }
20              
21             sub _ensure_der {
22 10     10   28 my ($pem_or_der_r) = \$_[0];
23              
24 10 100       60 if ( $$pem_or_der_r =~ m<\A-> ) {
25 6         21 _pem_to_der($$pem_or_der_r);
26             }
27              
28 10         17 return;
29             }
30              
31             sub _decode_macro {
32 22     22   47 my ( $self, $der_r, $macro ) = ( shift, \$_[0], $_[1] );
33              
34 22         90 my $parser = $self->{'_asn1'}->find_or_die($macro);
35              
36 22         386 return $parser->decode($$der_r);
37             }
38              
39             sub private {
40 3     3 0 7 my ($self, $pem_or_der) = @_;
41              
42 3         11 _ensure_der($pem_or_der);
43              
44 3   66     15 my $parsed = $self->_decode_rsa($pem_or_der) || do {
45             my $pkcs8 = $self->_decode_pkcs8($pem_or_der) or do {
46             die sprintf( "Failed to parse as either RSA or PKCS8: %s", $self->{'_asn1'}->error() );
47             };
48              
49             $self->_decode_rsa_within_pkcs8_or_die($pkcs8);
50             };
51              
52 3         434214 return $self->_new_private($parsed);
53             }
54              
55             #Like private(), but only does PKCS8.
56             sub private_pkcs8 {
57 2     2 0 6 my ($self, $pem_or_der) = @_;
58              
59 2         8 _ensure_der($pem_or_der);
60              
61 2 50       9 my $pkcs8 = $self->_decode_pkcs8($pem_or_der) or do {
62 0         0 die sprintf("Failed to parse PKCS8!");
63             };
64              
65 2         688 my $parsed = $self->_decode_rsa_within_pkcs8_or_die($pkcs8);
66              
67 2         282493 return $self->_new_private($parsed);
68             }
69              
70             #Checks for RSA format first, then falls back to PKCS8.
71             sub public {
72 3     3 0 6 my ($self, $pem_or_der) = @_;
73              
74 3         10 _ensure_der($pem_or_der);
75              
76 3   66     12 my $parsed = $self->_decode_rsa_public($pem_or_der) || do {
77             my $pkcs8 = $self->_decode_pkcs8_public($pem_or_der) or do {
78             die sprintf( "Failed to parse as either RSA or PKCS8: %s", $self->{'_asn1'}->error() );
79             };
80              
81             $self->_decode_rsa_public_within_pkcs8_or_die($pkcs8);
82             };
83              
84 3         146372 return $self->_new_public($parsed);
85             }
86              
87             #Like public(), but only does PKCS8.
88             sub public_pkcs8 {
89 2     2 0 10 my ($self, $pem_or_der) = @_;
90              
91 2         9 _ensure_der($pem_or_der);
92              
93 2 50       8 my $pkcs8 = $self->_decode_pkcs8_public($pem_or_der) or do {
94 0         0 die sprintf( "Failed to parse PKCS8: %s", $self->{'_asn1'}->error() );
95             };
96              
97 2         485 my $parsed = $self->_decode_rsa_public_within_pkcs8_or_die($pkcs8);
98              
99 2         61856 return $self->_new_public($parsed);
100             }
101              
102             #Checks for RSA format first, then falls back to PKCS8.
103             sub _decode_rsa {
104 7     7   20 my ($self, $der_r) = (shift, \$_[0]);
105              
106 7         26 return $self->_decode_macro( $$der_r, 'RSAPrivateKey' );
107             }
108              
109             sub _decode_rsa_public {
110 7     7   13 my ($self, $der_r) = (shift, \$_[0]);
111              
112 7         28 return $self->_decode_macro( $$der_r, 'RSAPublicKey' );
113             }
114              
115             sub _decode_rsa_within_pkcs8_or_die {
116 4     4   10 my ($self, $pkcs8_hr) = @_;
117              
118 4   33     15 return $self->_decode_rsa( $pkcs8_hr->{'privateKey'} ) || do {
119             die sprintf("Failed to parse RSA within PKCS8!");
120             };
121             }
122              
123             sub _decode_rsa_public_within_pkcs8_or_die {
124 4     4   7 my ($self, $pkcs8_hr) = @_;
125              
126 4   33     13 return $self->_decode_rsa_public( $pkcs8_hr->{'subjectPublicKey'}[0] ) || do {
127             die sprintf("Failed to parse RSA within PKCS8!");
128             };
129             }
130              
131             sub _decode_pkcs8 {
132 4     4   13 my ($self, $der_r) = (shift, \$_[0]);
133              
134 4         16 return $self->_decode_macro( $$der_r, 'PrivateKeyInfo' );
135             }
136              
137             sub _decode_pkcs8_public {
138 4     4   13 my ($self, $der_r) = (shift, \$_[0]);
139              
140 4         13 return $self->_decode_macro( $$der_r, 'SubjectPublicKeyInfo' );
141             }
142              
143             sub _new_public {
144 5     5   13 my ($self, $parsed_hr) = @_;
145              
146 5         19 local $parsed_hr->{'exponent'} = $parsed_hr->{'publicExponent'};
147              
148 5         50 return Crypt::RSA::Parse::Public->new($parsed_hr);
149             }
150              
151             sub _new_private {
152 5     5   13 my ($self, $parsed_hr) = @_;
153              
154 5         49 return Crypt::RSA::Parse::Private->new($parsed_hr);
155             }
156              
157             #Modifies in-place.
158             sub _pem_to_der {
159 6     6   14 local $Cpanel::Format::BASE64_MODULE = $_BASE64_MODULE;
160 6         23 $_[0] = Crypt::Format::pem2der(@_);
161              
162 6         465 return;
163             }
164              
165             1;