| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Crypt::X509; |
|
2
|
1
|
|
|
1
|
|
119549
|
use Carp; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
63
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
20
|
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
28
|
|
|
5
|
1
|
|
|
1
|
|
557
|
use Convert::ASN1 qw(:io :debug); |
|
|
1
|
|
|
|
|
35944
|
|
|
|
1
|
|
|
|
|
5576
|
|
|
6
|
|
|
|
|
|
|
require Exporter; |
|
7
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
8
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [qw()] ); |
|
9
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
|
10
|
|
|
|
|
|
|
#our @EXPORT = qw(error new not_before not_after serial); |
|
11
|
|
|
|
|
|
|
our $VERSION = '0.53'; |
|
12
|
|
|
|
|
|
|
my $parser = undef; |
|
13
|
|
|
|
|
|
|
my $asn = undef; |
|
14
|
|
|
|
|
|
|
my $error = undef; |
|
15
|
|
|
|
|
|
|
our %oid2enchash = ( |
|
16
|
|
|
|
|
|
|
'1.2.840.113549.1.1.1' => { 'enc' => 'RSA' }, |
|
17
|
|
|
|
|
|
|
'1.2.840.113549.1.1.2' => { 'enc' => 'RSA', 'hash' => 'MD2' }, |
|
18
|
|
|
|
|
|
|
'1.2.840.113549.1.1.3' => { 'enc' => 'RSA', 'hash' => 'MD4' }, |
|
19
|
|
|
|
|
|
|
'1.2.840.113549.1.1.4' => { 'enc' => 'RSA', 'hash' => 'MD5' }, |
|
20
|
|
|
|
|
|
|
'1.2.840.113549.1.1.5' => { 'enc' => 'RSA', 'hash' => 'SHA1' }, |
|
21
|
|
|
|
|
|
|
'1.2.840.113549.1.1.6' => { 'enc' => 'OAEP' }, |
|
22
|
|
|
|
|
|
|
'1.2.840.113549.1.1.11' => { 'enc' => 'RSA', 'hash' => 'SHA256' }, |
|
23
|
|
|
|
|
|
|
'1.2.840.113549.1.1.12' => { 'enc' => 'RSA', 'hash' => 'SHA384' }, |
|
24
|
|
|
|
|
|
|
'1.2.840.113549.1.1.13' => { 'enc' => 'RSA', 'hash' => 'SHA512' }, |
|
25
|
|
|
|
|
|
|
'1.2.840.113549.1.1.14' => { 'enc' => 'RSA', 'hash' => 'SHA224' } |
|
26
|
|
|
|
|
|
|
); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our %oid2attr = ( |
|
29
|
|
|
|
|
|
|
"2.5.4.3" => "CN", |
|
30
|
|
|
|
|
|
|
"2.5.4.4" => "SN", |
|
31
|
|
|
|
|
|
|
"2.5.4.42" => "GN", |
|
32
|
|
|
|
|
|
|
"2.5.4.5" => "serialNumber", |
|
33
|
|
|
|
|
|
|
"2.5.4.6" => "C", |
|
34
|
|
|
|
|
|
|
"2.5.4.7" => "L", |
|
35
|
|
|
|
|
|
|
"2.5.4.8" => "ST", |
|
36
|
|
|
|
|
|
|
"2.5.4.10" => "O", |
|
37
|
|
|
|
|
|
|
"2.5.4.11" => "OU", |
|
38
|
|
|
|
|
|
|
"1.2.840.113549.1.9.1" => "E", |
|
39
|
|
|
|
|
|
|
"0.9.2342.19200300.100.1.1" => "UID", |
|
40
|
|
|
|
|
|
|
"0.9.2342.19200300.100.1.25" => "DC", |
|
41
|
|
|
|
|
|
|
"0.2.262.1.10.7.20" => "nameDistinguisher" |
|
42
|
|
|
|
|
|
|
); |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 NAME |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Crypt::X509 - Parse a X.509 certificate |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
use Crypt::X509; |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
$decoded = Crypt::X509->new( cert => $cert ); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
$subject_email = $decoded->subject_email; |
|
55
|
|
|
|
|
|
|
print "do not use after: ".gmtime($decoded->not_after)." GMT\n"; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 REQUIRES |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Convert::ASN1 |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
B parses X.509 certificates. Methods are provided for accessing most |
|
64
|
|
|
|
|
|
|
certificate elements. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
It is based on the generic ASN.1 module by Graham Barr, on the F |
|
67
|
|
|
|
|
|
|
example by Norbert Klasen and contributions on the perl-ldap-dev-Mailinglist |
|
68
|
|
|
|
|
|
|
by Chriss Ridd. |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=head2 new ( OPTIONS ) |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
Creates and returns a parsed X.509 certificate hash, containing the parsed |
|
75
|
|
|
|
|
|
|
contents. The data is organised as specified in RFC 2459. |
|
76
|
|
|
|
|
|
|
By default only the first ASN.1 Layer is decoded. Nested decoding |
|
77
|
|
|
|
|
|
|
is done automagically through the data access methods. |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=over 4 |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item cert =E $certificate |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
A variable containing the DER formatted certificate to be parsed |
|
84
|
|
|
|
|
|
|
(eg. as stored in C attribute in an |
|
85
|
|
|
|
|
|
|
LDAP-directory). |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=back |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
use Crypt::X509; |
|
90
|
|
|
|
|
|
|
use Data::Dumper; |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
print Dumper($decoded); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut back |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub new { |
|
99
|
11
|
|
|
11
|
1
|
2735
|
my ( $class, %args ) = @_; |
|
100
|
11
|
100
|
100
|
|
|
59
|
if ( !defined($parser) || $parser->error ) { |
|
101
|
2
|
|
|
|
|
12
|
$parser = _init(); |
|
102
|
|
|
|
|
|
|
} |
|
103
|
11
|
|
|
|
|
83
|
my $self = $parser->decode( $args{'cert'} ); |
|
104
|
11
|
|
|
|
|
47560
|
$self->{"_error"} = $parser->error; |
|
105
|
11
|
|
|
|
|
59
|
bless( $self, $class ); |
|
106
|
11
|
|
|
|
|
117
|
return $self; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head1 METHODS |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head2 error |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Returns the last error from parsing, C when no error occured. |
|
114
|
|
|
|
|
|
|
This error is updated on deeper parsing with the data access methods. |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
118
|
|
|
|
|
|
|
if ($decoded->error) { |
|
119
|
|
|
|
|
|
|
warn "Error on parsing Certificate:".$decoded->error; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut back |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub error { |
|
125
|
10
|
|
|
10
|
1
|
1139
|
my $self = shift; |
|
126
|
10
|
|
|
|
|
63
|
return $self->{"_error"}; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=head1 DATA ACCESS METHODS |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
You can access all parsed data directly from the returned hash. For convenience |
|
132
|
|
|
|
|
|
|
the following methods have been implemented to give quick access to the most-used |
|
133
|
|
|
|
|
|
|
certificate attributes. |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=head2 version |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Returns the certificate's version as an integer. NOTE that version is defined as |
|
138
|
|
|
|
|
|
|
an Integer where 0 = v1, 1 = v2, and 2 = v3. |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut back |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub version { |
|
143
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
144
|
0
|
|
|
|
|
0
|
return $self->{tbsCertificate}{version}; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head2 version_string |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Returns the certificate's version as a string value. |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut back |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub version_string { |
|
154
|
1
|
|
|
1
|
1
|
4
|
my $self = shift; |
|
155
|
1
|
|
|
|
|
5
|
my $v = $self->{tbsCertificate}{version}; |
|
156
|
1
|
50
|
|
|
|
7
|
return "v1" if $v == 0; |
|
157
|
1
|
50
|
|
|
|
6
|
return "v2" if $v == 1; |
|
158
|
1
|
50
|
|
|
|
6
|
return "v3" if $v == 2; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 serial |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
returns the serial number (integer or Math::BigInt Object, that gets automagic |
|
164
|
|
|
|
|
|
|
evaluated in scalar context) from the certificate |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
168
|
|
|
|
|
|
|
print "Certificate has serial number:".$decoded->serial."\n"; |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=cut back |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub serial { |
|
173
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
174
|
0
|
|
|
|
|
0
|
return $self->{tbsCertificate}{serialNumber}; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head2 not_before |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
returns the GMT-timestamp of the certificate's beginning date of validity. |
|
180
|
|
|
|
|
|
|
If the Certificate holds this Entry in utcTime, it is guaranteed by the |
|
181
|
|
|
|
|
|
|
RFC to been correct. |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
As utcTime is limited to 32-bit values (like unix-timestamps) newer certificates |
|
184
|
|
|
|
|
|
|
hold the timesamps as "generalTime"-entries. B
|
|
185
|
|
|
|
|
|
|
are not well defined in the RFC and |
|
186
|
|
|
|
|
|
|
are returned by this module unmodified>, if no utcTime-entry is found. |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
190
|
|
|
|
|
|
|
if ($decoded->notBefore < time()) { |
|
191
|
|
|
|
|
|
|
warn "Certificate: not yet valid!"; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut back |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub not_before { |
|
197
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
198
|
0
|
0
|
|
|
|
0
|
if ( $self->{tbsCertificate}{validity}{notBefore}{utcTime} ) { |
|
|
|
0
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
0
|
return $self->{tbsCertificate}{validity}{notBefore}{utcTime}; |
|
200
|
|
|
|
|
|
|
} elsif ( $self->{tbsCertificate}{validity}{notBefore}{generalTime} ) { |
|
201
|
0
|
|
|
|
|
0
|
return $self->{tbsCertificate}{validity}{notBefore}{generalTime}; |
|
202
|
|
|
|
|
|
|
} else { |
|
203
|
0
|
|
|
|
|
0
|
return undef; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 not_after |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
returns the GMT-timestamp of the certificate's ending date of validity. |
|
210
|
|
|
|
|
|
|
If the Certificate holds this Entry in utcTime, it is guaranteed by the |
|
211
|
|
|
|
|
|
|
RFC to been correct. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
As utcTime is limited to 32-bit values (like unix-timestamps) newer certificates |
|
214
|
|
|
|
|
|
|
hold the timesamps as "generalTime"-entries. B
|
|
215
|
|
|
|
|
|
|
are not well defined in the RFC and |
|
216
|
|
|
|
|
|
|
are returned by this module unmodified>, if no utcTime-entry is found. |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
220
|
|
|
|
|
|
|
print "Certificate expires on ".gmtime($decoded->not_after)." GMT\n"; |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut back |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub not_after { |
|
225
|
4
|
|
|
4
|
1
|
27
|
my $self = shift; |
|
226
|
4
|
100
|
|
|
|
18
|
if ( $self->{tbsCertificate}{validity}{notAfter}{utcTime} ) { |
|
|
|
50
|
|
|
|
|
|
|
227
|
2
|
|
|
|
|
11
|
return $self->{tbsCertificate}{validity}{notAfter}{utcTime}; |
|
228
|
|
|
|
|
|
|
} elsif ( $self->{tbsCertificate}{validity}{notAfter}{generalTime} ) { |
|
229
|
2
|
|
|
|
|
14
|
return $self->{tbsCertificate}{validity}{notAfter}{generalTime}; |
|
230
|
|
|
|
|
|
|
} else { |
|
231
|
0
|
|
|
|
|
0
|
return undef; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 signature |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
Return's the certificate's signature in binary DER format. |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=cut back |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub signature { |
|
242
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
243
|
1
|
|
|
|
|
6
|
return $self->{signature}[0]; |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head2 pubkey |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Returns the certificate's public key in binary DER format. |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut back |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub pubkey { |
|
253
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
254
|
1
|
|
|
|
|
5
|
return $self->{tbsCertificate}{subjectPublicKeyInfo}{subjectPublicKey}[0]; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head2 pubkey_size |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
Returns the certificate's public key size. |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=cut back |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub pubkey_size { |
|
264
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
265
|
0
|
|
|
|
|
0
|
return $self->{tbsCertificate}{subjectPublicKeyInfo}{subjectPublicKey}[1]; |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=head2 pubkey_algorithm |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
Returns the algorithm as OID string which the public key was created with. |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=cut back |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub pubkey_algorithm { |
|
275
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
276
|
1
|
|
|
|
|
4
|
return $self->{tbsCertificate}{subjectPublicKeyInfo}{algorithm}{algorithm}; |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=head2 PubKeyAlg |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
returns the subject public key encryption algorithm (e.g. 'RSA') as string. |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
284
|
|
|
|
|
|
|
print "Certificate public key is encrypted with:".$decoded->PubKeyAlg."\n"; |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Example Output: Certificate public key is encrypted with: RSA |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut back |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub PubKeyAlg { |
|
291
|
2
|
|
|
2
|
1
|
6
|
my $self = shift; |
|
292
|
2
|
|
|
|
|
16
|
return $oid2enchash{ $self->{tbsCertificate}{subjectPublicKeyInfo}{algorithm}{algorithm} }->{'enc'}; |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head2 pubkey_components |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
If this certificate contains an RSA key, this function returns a |
|
298
|
|
|
|
|
|
|
hashref { modulus => $m, exponent => $e) from that key; each value in |
|
299
|
|
|
|
|
|
|
the hash will be an integer scalar or a Math::BigInt object. |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
For other pubkey types, it returns undef (implementations welcome!). |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut back |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub pubkey_components { |
|
306
|
2
|
|
|
2
|
1
|
23944
|
my $self = shift; |
|
307
|
2
|
50
|
|
|
|
8
|
if ($self->PubKeyAlg() eq 'RSA') { |
|
308
|
2
|
|
|
|
|
8
|
my $parser = _init('RSAPubKeyInfo'); |
|
309
|
2
|
|
|
|
|
9
|
my $values = $parser->decode($self->{tbsCertificate}{subjectPublicKeyInfo}{subjectPublicKey}[0]); |
|
310
|
2
|
|
|
|
|
149926
|
return $values; |
|
311
|
|
|
|
|
|
|
} else { |
|
312
|
0
|
|
|
|
|
0
|
return undef; |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 sig_algorithm |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Returns the certificate's signature algorithm as OID string |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
321
|
|
|
|
|
|
|
print "Certificate signature is encrypted with:".$decoded->sig_algorithm."\n";> |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Example Output: Certificate signature is encrypted with: 1.2.840.113549.1.1.5 |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=cut back |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub sig_algorithm { |
|
328
|
1
|
|
|
1
|
1
|
4
|
my $self = shift; |
|
329
|
1
|
|
|
|
|
5
|
return $self->{tbsCertificate}{signature}{algorithm}; |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head2 SigEncAlg |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
returns the signature encryption algorithm (e.g. 'RSA') as string. |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
337
|
|
|
|
|
|
|
print "Certificate signature is encrypted with:".$decoded->SigEncAlg."\n"; |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Example Output: Certificate signature is encrypted with: RSA |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=cut back |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub SigEncAlg { |
|
344
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
345
|
0
|
|
|
|
|
0
|
return $oid2enchash{ $self->{'signatureAlgorithm'}->{'algorithm'} }->{'enc'}; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head2 SigHashAlg |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
returns the signature hashing algorithm (e.g. 'SHA1') as string. |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
353
|
|
|
|
|
|
|
print "Certificate signature is hashed with:".$decoded->SigHashAlg."\n"; |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Example Output: Certificate signature is encrypted with: SHA1 |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=cut back |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub SigHashAlg { |
|
360
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
361
|
1
|
|
|
|
|
8
|
return $oid2enchash{ $self->{'signatureAlgorithm'}->{'algorithm'} }->{'hash'}; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
######################################################################### |
|
364
|
|
|
|
|
|
|
# accessors - subject |
|
365
|
|
|
|
|
|
|
######################################################################### |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head2 Subject |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
returns a pointer to an array of strings containing subject nameparts of the |
|
370
|
|
|
|
|
|
|
certificate. Attributenames for the most common Attributes are translated |
|
371
|
|
|
|
|
|
|
from the OID-Numbers, unknown numbers are output verbatim. |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
$decoded= Convert::ASN1::X509->new($cert); |
|
374
|
|
|
|
|
|
|
print "DN for this Certificate is:".join(',',@{$decoded->Subject})."\n"; |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=cut back |
|
377
|
|
|
|
|
|
|
sub Subject { |
|
378
|
3
|
|
|
3
|
1
|
11
|
my $self = shift; |
|
379
|
3
|
|
|
|
|
5
|
my ( $i, $type ); |
|
380
|
3
|
|
|
|
|
9
|
my $subjrdn = $self->{'tbsCertificate'}->{'subject'}->{'rdnSequence'}; |
|
381
|
3
|
|
|
|
|
6
|
$self->{'tbsCertificate'}->{'subject'}->{'dn'} = []; |
|
382
|
3
|
|
|
|
|
6
|
my $subjdn = $self->{'tbsCertificate'}->{'subject'}->{'dn'}; |
|
383
|
3
|
|
|
|
|
6
|
foreach my $subj ( @{$subjrdn} ) { |
|
|
3
|
|
|
|
|
6
|
|
|
384
|
11
|
|
|
|
|
15
|
foreach my $i ( @{$subj} ) { |
|
|
11
|
|
|
|
|
16
|
|
|
385
|
12
|
50
|
|
|
|
28
|
if ( $oid2attr{ $i->{'type'} } ) { |
|
386
|
12
|
|
|
|
|
20
|
$type = $oid2attr{ $i->{'type'} }; |
|
387
|
|
|
|
|
|
|
} else { |
|
388
|
0
|
|
|
|
|
0
|
$type = $i->{'type'}; |
|
389
|
|
|
|
|
|
|
} |
|
390
|
12
|
|
|
|
|
16
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
12
|
|
|
|
|
30
|
|
|
391
|
12
|
|
|
|
|
14
|
push @{$subjdn}, $type . "=" . $i->{'value'}->{ $key[0] }; |
|
|
12
|
|
|
|
|
38
|
|
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
} |
|
394
|
3
|
|
|
|
|
19
|
return $subjdn; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub _subject_part { |
|
398
|
5
|
|
|
5
|
|
8
|
my $self = shift; |
|
399
|
5
|
|
|
|
|
9
|
my $oid = shift; |
|
400
|
5
|
|
|
|
|
11
|
my $subjrdn = $self->{'tbsCertificate'}->{'subject'}->{'rdnSequence'}; |
|
401
|
5
|
|
|
|
|
6
|
foreach my $subj ( @{$subjrdn} ) { |
|
|
5
|
|
|
|
|
11
|
|
|
402
|
14
|
|
|
|
|
19
|
foreach my $i ( @{$subj} ) { |
|
|
14
|
|
|
|
|
21
|
|
|
403
|
14
|
100
|
|
|
|
32
|
if ( $i->{'type'} eq $oid ) { |
|
404
|
3
|
|
|
|
|
4
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
3
|
|
|
|
|
10
|
|
|
405
|
3
|
|
|
|
|
17
|
return $i->{'value'}->{ $key[0] }; |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
} |
|
409
|
2
|
|
|
|
|
10
|
return undef; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 subject_country |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
Returns the string value for subject's country (= the value with the |
|
415
|
|
|
|
|
|
|
OID 2.5.4.6 or in DN Syntax everything after C). |
|
416
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no country attribute. |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=cut back |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub subject_country { |
|
421
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
422
|
1
|
|
|
|
|
3
|
return _subject_part( $self, '2.5.4.6' ); |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=head2 subject_locality |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Returns the string value for subject's locality (= the value with the |
|
428
|
|
|
|
|
|
|
OID 2.5.4.7 or in DN Syntax everything after C). |
|
429
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no locality attribute. |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=cut back |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub subject_locality { |
|
434
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
435
|
0
|
|
|
|
|
0
|
return _subject_part( $self, '2.5.4.7' ); |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head2 subject_state |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Returns the string value for subject's state or province (= the value with the |
|
441
|
|
|
|
|
|
|
OID 2.5.4.8 or in DN Syntax everything after C). |
|
442
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no state attribute. |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=cut back |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub subject_state { |
|
447
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
448
|
1
|
|
|
|
|
4
|
return _subject_part( $self, '2.5.4.8' ); |
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head2 subject_org |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Returns the string value for subject's organization (= the value with the |
|
454
|
|
|
|
|
|
|
OID 2.5.4.10 or in DN Syntax everything after C). |
|
455
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no organization attribute. |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=cut back |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub subject_org { |
|
460
|
1
|
|
|
1
|
1
|
15
|
my $self = shift; |
|
461
|
1
|
|
|
|
|
6
|
return _subject_part( $self, '2.5.4.10' ); |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head2 subject_ou |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Returns the string value for subject's organizational unit (= the value with the |
|
467
|
|
|
|
|
|
|
OID 2.5.4.11 or in DN Syntax everything after C). |
|
468
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no organization attribute. |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=cut back |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub subject_ou { |
|
473
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
474
|
1
|
|
|
|
|
4
|
return _subject_part( $self, '2.5.4.11' ); |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head2 subject_cn |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Returns the string value for subject's common name (= the value with the |
|
480
|
|
|
|
|
|
|
OID 2.5.4.3 or in DN Syntax everything after C). |
|
481
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no common name attribute. |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=cut back |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
sub subject_cn { |
|
486
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
487
|
0
|
|
|
|
|
0
|
return _subject_part( $self, '2.5.4.3' ); |
|
488
|
|
|
|
|
|
|
} |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head2 subject_email |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Returns the string value for subject's email address (= the value with the |
|
493
|
|
|
|
|
|
|
OID 1.2.840.113549.1.9.1 or in DN Syntax everything after C). |
|
494
|
|
|
|
|
|
|
Only the first entry is returned. C if subject contains no email attribute. |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=cut back |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
sub subject_email { |
|
499
|
1
|
|
|
1
|
1
|
13
|
my $self = shift; |
|
500
|
1
|
|
|
|
|
4
|
return _subject_part( $self, '1.2.840.113549.1.9.1' ); |
|
501
|
|
|
|
|
|
|
} |
|
502
|
|
|
|
|
|
|
######################################################################### |
|
503
|
|
|
|
|
|
|
# accessors - issuer |
|
504
|
|
|
|
|
|
|
######################################################################### |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=head2 Issuer |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
returns a pointer to an array of strings building the DN of the certificate |
|
509
|
|
|
|
|
|
|
issuer (= the DN of the CA). Attributenames for the most common Attributes |
|
510
|
|
|
|
|
|
|
are translated from the OID-Numbers, unknown numbers are output verbatim. |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
$decoded= Crypt::X509->new($cert); |
|
513
|
|
|
|
|
|
|
print "Certificate was issued by:".join(',',@{$decoded->Issuer})."\n"; |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=cut back |
|
516
|
|
|
|
|
|
|
sub Issuer { |
|
517
|
3
|
|
|
3
|
1
|
8
|
my $self = shift; |
|
518
|
3
|
|
|
|
|
6
|
my ( $i, $type ); |
|
519
|
3
|
|
|
|
|
9
|
my $issuerdn = $self->{'tbsCertificate'}->{'issuer'}->{'rdnSequence'}; |
|
520
|
3
|
|
|
|
|
8
|
$self->{'tbsCertificate'}->{'issuer'}->{'dn'} = []; |
|
521
|
3
|
|
|
|
|
8
|
my $issuedn = $self->{'tbsCertificate'}->{'issuer'}->{'dn'}; |
|
522
|
3
|
|
|
|
|
5
|
foreach my $issue ( @{$issuerdn} ) { |
|
|
3
|
|
|
|
|
8
|
|
|
523
|
11
|
|
|
|
|
16
|
foreach my $i ( @{$issue} ) { |
|
|
11
|
|
|
|
|
16
|
|
|
524
|
12
|
50
|
|
|
|
32
|
if ( $oid2attr{ $i->{'type'} } ) { |
|
525
|
12
|
|
|
|
|
20
|
$type = $oid2attr{ $i->{'type'} }; |
|
526
|
|
|
|
|
|
|
} else { |
|
527
|
0
|
|
|
|
|
0
|
$type = $i->{'type'}; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
12
|
|
|
|
|
14
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
12
|
|
|
|
|
31
|
|
|
530
|
12
|
|
|
|
|
18
|
push @{$issuedn}, $type . "=" . $i->{'value'}->{ $key[0] }; |
|
|
12
|
|
|
|
|
40
|
|
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
} |
|
533
|
3
|
|
|
|
|
17
|
return $issuedn; |
|
534
|
|
|
|
|
|
|
} |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub _issuer_part { |
|
537
|
6
|
|
|
6
|
|
9
|
my $self = shift; |
|
538
|
6
|
|
|
|
|
11
|
my $oid = shift; |
|
539
|
6
|
|
|
|
|
12
|
my $issuerrdn = $self->{'tbsCertificate'}->{'issuer'}->{'rdnSequence'}; |
|
540
|
6
|
|
|
|
|
8
|
foreach my $issue ( @{$issuerrdn} ) { |
|
|
6
|
|
|
|
|
13
|
|
|
541
|
15
|
|
|
|
|
20
|
foreach my $i ( @{$issue} ) { |
|
|
15
|
|
|
|
|
23
|
|
|
542
|
15
|
100
|
|
|
|
36
|
if ( $i->{'type'} eq $oid ) { |
|
543
|
3
|
|
|
|
|
4
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
3
|
|
|
|
|
11
|
|
|
544
|
3
|
|
|
|
|
18
|
return $i->{'value'}->{ $key[0] }; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
} |
|
548
|
3
|
|
|
|
|
13
|
return undef; |
|
549
|
|
|
|
|
|
|
} |
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head2 issuer_cn |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Returns the string value for issuer's common name (= the value with the |
|
554
|
|
|
|
|
|
|
OID 2.5.4.3 or in DN Syntax everything after C). |
|
555
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no common name attribute. |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=cut back |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
sub issuer_cn { |
|
560
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
561
|
1
|
|
|
|
|
4
|
return _issuer_part( $self, '2.5.4.3' ); |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=head2 issuer_country |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
Returns the string value for issuer's country (= the value with the |
|
567
|
|
|
|
|
|
|
OID 2.5.4.6 or in DN Syntax everything after C). |
|
568
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no country attribute. |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=cut back |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub issuer_country { |
|
573
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
574
|
1
|
|
|
|
|
2
|
return _issuer_part( $self, '2.5.4.6' ); |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=head2 issuer_state |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
Returns the string value for issuer's state or province (= the value with the |
|
580
|
|
|
|
|
|
|
OID 2.5.4.8 or in DN Syntax everything after C). |
|
581
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no state attribute. |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=cut back |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub issuer_state { |
|
586
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
587
|
1
|
|
|
|
|
3
|
return _issuer_part( $self, '2.5.4.8' ); |
|
588
|
|
|
|
|
|
|
} |
|
589
|
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head2 issuer_locality |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Returns the string value for issuer's locality (= the value with the |
|
593
|
|
|
|
|
|
|
OID 2.5.4.7 or in DN Syntax everything after C). |
|
594
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no locality attribute. |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=cut back |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
sub issuer_locality { |
|
599
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
600
|
1
|
|
|
|
|
5
|
return _issuer_part( $self, '2.5.4.7' ); |
|
601
|
|
|
|
|
|
|
} |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=head2 issuer_org |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
Returns the string value for issuer's organization (= the value with the |
|
606
|
|
|
|
|
|
|
OID 2.5.4.10 or in DN Syntax everything after C). |
|
607
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no organization attribute. |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=cut back |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
sub issuer_org { |
|
612
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
613
|
1
|
|
|
|
|
5
|
return _issuer_part( $self, '2.5.4.10' ); |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=head2 issuer_email |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Returns the string value for issuer's email address (= the value with the |
|
619
|
|
|
|
|
|
|
OID 1.2.840.113549.1.9.1 or in DN Syntax everything after C). |
|
620
|
|
|
|
|
|
|
Only the first entry is returned. C if issuer contains no email attribute. |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=cut back |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
sub issuer_email { |
|
625
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
626
|
1
|
|
|
|
|
5
|
return _issuer_part( $self, '1.2.840.113549.1.9.1' ); |
|
627
|
|
|
|
|
|
|
} |
|
628
|
|
|
|
|
|
|
######################################################################### |
|
629
|
|
|
|
|
|
|
# accessors - extensions (automate this) |
|
630
|
|
|
|
|
|
|
######################################################################### |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head2 KeyUsage |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
returns a pointer to an array of strings describing the valid Usages |
|
635
|
|
|
|
|
|
|
for this certificate. C is returned, when the extension is not set in the |
|
636
|
|
|
|
|
|
|
certificate. |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
If the extension is marked critical, this is also reported. |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
$decoded= Crypt::X509->new(cert => $cert); |
|
641
|
|
|
|
|
|
|
print "Allowed usages for this Certificate are:\n".join("\n",@{$decoded->KeyUsage})."\n"; |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
Example Output: |
|
644
|
|
|
|
|
|
|
Allowed usages for this Certificate are: |
|
645
|
|
|
|
|
|
|
critical |
|
646
|
|
|
|
|
|
|
digitalSignature |
|
647
|
|
|
|
|
|
|
keyEncipherment |
|
648
|
|
|
|
|
|
|
dataEncipherment |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=cut back |
|
651
|
|
|
|
|
|
|
sub KeyUsage { |
|
652
|
3
|
|
|
3
|
1
|
8
|
my $self = shift; |
|
653
|
3
|
|
|
|
|
4
|
my $ext; |
|
654
|
3
|
|
|
|
|
7
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
655
|
3
|
50
|
|
|
|
10
|
if ( !defined $exts ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
656
|
|
|
|
|
|
|
; # no extensions in certificate |
|
657
|
3
|
|
|
|
|
6
|
foreach $ext ( @{$exts} ) { |
|
|
3
|
|
|
|
|
7
|
|
|
658
|
5
|
100
|
|
|
|
24
|
if ( $ext->{'extnID'} eq '2.5.29.15' ) { #OID for keyusage |
|
659
|
3
|
|
|
|
|
9
|
my $parsKeyU = _init('KeyUsage'); # get a parser for this |
|
660
|
3
|
|
|
|
|
10
|
my $keyusage = $parsKeyU->decode( $ext->{'extnValue'} ); # decode the value |
|
661
|
3
|
50
|
|
|
|
227
|
if ( $parsKeyU->error ) { |
|
662
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $parsKeyU->error; |
|
663
|
0
|
|
|
|
|
0
|
return undef; |
|
664
|
|
|
|
|
|
|
} |
|
665
|
3
|
|
|
|
|
16
|
my $keyu = unpack( "n", ${$keyusage}[0] . ${$keyusage}[1] ) & 0xff80; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
11
|
|
|
666
|
3
|
|
|
|
|
8
|
$ext->{'usage'} = []; |
|
667
|
3
|
50
|
|
|
|
8
|
if ( $ext->{'critical'} ) { push @{ $ext->{'usage'} }, "critical"; } # mark as critical, if appropriate |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
7
|
|
|
668
|
3
|
50
|
|
|
|
8
|
if ( $keyu & 0x8000 ) { push @{ $ext->{'usage'} }, "digitalSignature"; } |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
5
|
|
|
669
|
3
|
50
|
|
|
|
8
|
if ( $keyu & 0x4000 ) { push @{ $ext->{'usage'} }, "nonRepudiation"; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
670
|
3
|
100
|
|
|
|
7
|
if ( $keyu & 0x2000 ) { push @{ $ext->{'usage'} }, "keyEncipherment"; } |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
3
|
|
|
671
|
3
|
100
|
|
|
|
7
|
if ( $keyu & 0x1000 ) { push @{ $ext->{'usage'} }, "dataEncipherment"; } |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
5
|
|
|
672
|
3
|
100
|
|
|
|
6
|
if ( $keyu & 0x0800 ) { push @{ $ext->{'usage'} }, "keyAgreement"; } |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
673
|
3
|
50
|
|
|
|
7
|
if ( $keyu & 0x0400 ) { push @{ $ext->{'usage'} }, "keyCertSign"; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
674
|
3
|
50
|
|
|
|
16
|
if ( $keyu & 0x0200 ) { push @{ $ext->{'usage'} }, "cRLSign"; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
675
|
3
|
50
|
|
|
|
15
|
if ( $keyu & 0x0100 ) { push @{ $ext->{'usage'} }, "encipherOnly"; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
676
|
3
|
50
|
|
|
|
9
|
if ( $keyu & 0x0080 ) { push @{ $ext->{'usage'} }, "decipherOnly"; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
677
|
3
|
|
|
|
|
33
|
return $ext->{'usage'}; |
|
678
|
|
|
|
|
|
|
} |
|
679
|
|
|
|
|
|
|
} |
|
680
|
0
|
|
|
|
|
0
|
return undef; # keyusage extension not found |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=head2 ExtKeyUsage |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
returns a pointer to an array of ExtKeyUsage strings (or OIDs for unknown OIDs) or |
|
686
|
|
|
|
|
|
|
C if the extension is not filled. OIDs of the following ExtKeyUsages are known: |
|
687
|
|
|
|
|
|
|
serverAuth, clientAuth, codeSigning, emailProtection, timeStamping, OCSPSigning |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
If the extension is marked critical, this is also reported. |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
$decoded= Crypt::X509->new($cert); |
|
692
|
|
|
|
|
|
|
print "ExtKeyUsage extension of this Certificates is: ", join(", ", @{$decoded->ExtKeyUsage}), "\n"; |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
Example Output: ExtKeyUsage extension of this Certificates is: critical, serverAuth |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=cut back |
|
697
|
|
|
|
|
|
|
our %oid2extkeyusage = ( |
|
698
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.1' => 'serverAuth', |
|
699
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.2' => 'clientAuth', |
|
700
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.3' => 'codeSigning', |
|
701
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.4' => 'emailProtection', |
|
702
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.8' => 'timeStamping', |
|
703
|
|
|
|
|
|
|
'1.3.6.1.5.5.7.3.9' => 'OCSPSigning', |
|
704
|
|
|
|
|
|
|
); |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
sub ExtKeyUsage { |
|
707
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
|
708
|
2
|
|
|
|
|
4
|
my $ext; |
|
709
|
2
|
|
|
|
|
5
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
710
|
2
|
50
|
|
|
|
7
|
if ( !defined $exts ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
711
|
|
|
|
|
|
|
; # no extensions in certificate |
|
712
|
2
|
|
|
|
|
3
|
foreach $ext ( @{$exts} ) { |
|
|
2
|
|
|
|
|
4
|
|
|
713
|
14
|
100
|
|
|
|
28
|
if ( $ext->{'extnID'} eq '2.5.29.37' ) { #OID for ExtKeyUsage |
|
714
|
2
|
100
|
|
|
|
12
|
return $ext->{'oids'} if defined $ext->{'oids'}; |
|
715
|
1
|
|
|
|
|
6
|
my $parsExtKeyUsage = _init('ExtKeyUsageSyntax'); # get a parser for this |
|
716
|
1
|
|
|
|
|
4
|
my $oids = $parsExtKeyUsage->decode( $ext->{'extnValue'} ); # decode the value |
|
717
|
1
|
50
|
|
|
|
165
|
if ( $parsExtKeyUsage->error ) { |
|
718
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $parsExtKeyUsage->error; |
|
719
|
0
|
|
|
|
|
0
|
return undef; |
|
720
|
|
|
|
|
|
|
} |
|
721
|
1
|
50
|
|
|
|
7
|
$ext->{'oids'} = [ map { $oid2extkeyusage{$_} || $_ } @$oids ]; |
|
|
2
|
|
|
|
|
12
|
|
|
722
|
1
|
50
|
|
|
|
7
|
if ( $ext->{'critical'} ) { unshift @{ $ext->{'oids'} }, "critical"; } # mark as critical, if appropriate |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
723
|
1
|
|
|
|
|
8
|
return $ext->{'oids'}; |
|
724
|
|
|
|
|
|
|
} |
|
725
|
|
|
|
|
|
|
} |
|
726
|
0
|
|
|
|
|
0
|
return undef; |
|
727
|
|
|
|
|
|
|
} |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=head2 SubjectAltName |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
returns a pointer to an array of strings containing alternative Subjectnames or |
|
732
|
|
|
|
|
|
|
C if the extension is not filled. Usually this Extension holds the e-Mail |
|
733
|
|
|
|
|
|
|
address for person-certificates or DNS-Names for server certificates. |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
It also pre-pends the field type (ie rfc822Name) to the returned value. |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
$decoded= Crypt::X509->new($cert); |
|
738
|
|
|
|
|
|
|
print "E-Mail or Hostnames in this Certificates is/are:", join(", ", @{$decoded->SubjectAltName}), "\n"; |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
Example Output: E-Mail or Hostnames in this Certificates is/are: rfc822Name=user@server.com |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=cut back |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
sub SubjectAltName { |
|
745
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
746
|
1
|
|
|
|
|
2
|
my $ext; |
|
747
|
1
|
|
|
|
|
5
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
748
|
1
|
50
|
|
|
|
4
|
if ( !defined $exts ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
749
|
|
|
|
|
|
|
; # no extensions in certificate |
|
750
|
1
|
|
|
|
|
2
|
foreach $ext ( @{$exts} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
751
|
5
|
100
|
|
|
|
12
|
if ( $ext->{'extnID'} eq '2.5.29.17' ) { #OID for SubjectAltName |
|
752
|
1
|
|
|
|
|
5
|
my $parsSubjAlt = _init('SubjectAltName'); # get a parser for this |
|
753
|
1
|
|
|
|
|
4
|
my $altnames = $parsSubjAlt->decode( $ext->{'extnValue'} ); # decode the value |
|
754
|
1
|
50
|
|
|
|
145
|
if ( $parsSubjAlt->error ) { |
|
755
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $parsSubjAlt->error; |
|
756
|
0
|
|
|
|
|
0
|
return undef; |
|
757
|
|
|
|
|
|
|
} |
|
758
|
1
|
|
|
|
|
6
|
$ext->{'names'} = []; |
|
759
|
1
|
|
|
|
|
2
|
foreach my $name ( @{$altnames} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
760
|
1
|
|
|
|
|
2
|
foreach my $value ( keys %{$name} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
761
|
1
|
|
|
|
|
2
|
push @{ $ext->{'names'} }, "$value=" . $name->{$value}; |
|
|
1
|
|
|
|
|
5
|
|
|
762
|
|
|
|
|
|
|
} |
|
763
|
|
|
|
|
|
|
} |
|
764
|
1
|
|
|
|
|
9
|
return $ext->{'names'}; |
|
765
|
|
|
|
|
|
|
} |
|
766
|
|
|
|
|
|
|
} |
|
767
|
0
|
|
|
|
|
0
|
return undef; |
|
768
|
|
|
|
|
|
|
} |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=head2 DecodedSubjectAltNames |
|
771
|
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
Returns a pointer to an array of strings containing all the alternative subject name |
|
773
|
|
|
|
|
|
|
extensions. |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Each such extension is represented as a decoded ASN.1 value, i.e. a pointer to a list |
|
776
|
|
|
|
|
|
|
of pointers to objects, each object having a single key with the type of the alternative |
|
777
|
|
|
|
|
|
|
name and a value specific to that type. |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
Example return value: |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
[ |
|
782
|
|
|
|
|
|
|
[ |
|
783
|
|
|
|
|
|
|
{ |
|
784
|
|
|
|
|
|
|
'directoryName' => { |
|
785
|
|
|
|
|
|
|
'rdnSequence' => [ |
|
786
|
|
|
|
|
|
|
[ |
|
787
|
|
|
|
|
|
|
{ |
|
788
|
|
|
|
|
|
|
'value' => { 'utf8String' => 'example' }, |
|
789
|
|
|
|
|
|
|
'type' => '2.5.4.3' |
|
790
|
|
|
|
|
|
|
} |
|
791
|
|
|
|
|
|
|
] |
|
792
|
|
|
|
|
|
|
] |
|
793
|
|
|
|
|
|
|
} |
|
794
|
|
|
|
|
|
|
}, |
|
795
|
|
|
|
|
|
|
{ |
|
796
|
|
|
|
|
|
|
'dNSName' => 'example.com' |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
] |
|
799
|
|
|
|
|
|
|
] |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
=cut back |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
sub DecodedSubjectAltNames { |
|
804
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
|
805
|
2
|
|
|
|
|
7
|
my @sans = (); |
|
806
|
2
|
|
|
|
|
6
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
807
|
2
|
|
|
|
|
4
|
foreach my $ext ( @{$exts} ) { |
|
|
2
|
|
|
|
|
6
|
|
|
808
|
9
|
100
|
|
|
|
23
|
if ( $ext->{'extnID'} eq '2.5.29.17' ) { #OID for subjectAltName |
|
809
|
2
|
|
|
|
|
6
|
my $parsSubjAlt = _init('SubjectAltName'); |
|
810
|
2
|
|
|
|
|
11
|
my $altnames = $parsSubjAlt->decode( $ext->{'extnValue'} ); |
|
811
|
2
|
50
|
|
|
|
539
|
if ( $parsSubjAlt->error ) { |
|
812
|
0
|
|
|
|
|
0
|
$self->{'_error'} = $parsSubjAlt->error; |
|
813
|
0
|
|
|
|
|
0
|
return undef; |
|
814
|
|
|
|
|
|
|
} |
|
815
|
2
|
|
|
|
|
13
|
push @sans, $altnames; |
|
816
|
|
|
|
|
|
|
} |
|
817
|
|
|
|
|
|
|
} |
|
818
|
2
|
|
|
|
|
22
|
return \@sans; |
|
819
|
|
|
|
|
|
|
} |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
######################################################################### |
|
822
|
|
|
|
|
|
|
# accessors - authorityCertIssuer |
|
823
|
|
|
|
|
|
|
######################################################################### |
|
824
|
|
|
|
|
|
|
sub _AuthorityKeyIdentifier { |
|
825
|
7
|
|
|
7
|
|
13
|
my $self = shift; |
|
826
|
7
|
|
|
|
|
9
|
my $ext; |
|
827
|
7
|
|
|
|
|
13
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
828
|
7
|
50
|
|
|
|
21
|
if ( !defined $exts ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
829
|
|
|
|
|
|
|
; # no extensions in certificate |
|
830
|
7
|
100
|
|
|
|
16
|
if ( defined $self->{'tbsCertificate'}{'AuthorityKeyIdentifier'} ) { |
|
831
|
6
|
|
|
|
|
14
|
return ( $self->{'tbsCertificate'}{'AuthorityKeyIdentifier'} ); |
|
832
|
|
|
|
|
|
|
} |
|
833
|
1
|
|
|
|
|
2
|
foreach $ext ( @{$exts} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
834
|
10
|
100
|
|
|
|
19
|
if ( $ext->{'extnID'} eq '2.5.29.35' ) { #OID for AuthorityKeyIdentifier |
|
835
|
1
|
|
|
|
|
3
|
my $pars = _init('AuthorityKeyIdentifier'); # get a parser for this |
|
836
|
1
|
|
|
|
|
4
|
$self->{'tbsCertificate'}{'AuthorityKeyIdentifier'} = $pars->decode( $ext->{'extnValue'} ); # decode the value |
|
837
|
1
|
50
|
|
|
|
863
|
if ( $pars->error ) { |
|
838
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $pars->error; |
|
839
|
0
|
|
|
|
|
0
|
return undef; |
|
840
|
|
|
|
|
|
|
} |
|
841
|
1
|
|
|
|
|
9
|
return $self->{'tbsCertificate'}{'AuthorityKeyIdentifier'}; |
|
842
|
|
|
|
|
|
|
} |
|
843
|
|
|
|
|
|
|
} |
|
844
|
0
|
|
|
|
|
0
|
return undef; |
|
845
|
|
|
|
|
|
|
} |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=head2 authorityCertIssuer |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
returns a pointer to an array of strings building the DN of the Authority Cert |
|
850
|
|
|
|
|
|
|
Issuer. Attributenames for the most common Attributes |
|
851
|
|
|
|
|
|
|
are translated from the OID-Numbers, unknown numbers are output verbatim. |
|
852
|
|
|
|
|
|
|
undef if the extension is not set in the certificate. |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
$decoded= Crypt::X509->new($cert); |
|
855
|
|
|
|
|
|
|
print "Certificate was authorised by:".join(',',@{$decoded->authorityCertIssuer})."\n"; |
|
856
|
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
=cut back |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
sub authorityCertIssuer { |
|
860
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
861
|
1
|
|
|
|
|
3
|
my ( $i, $type ); |
|
862
|
1
|
|
|
|
|
4
|
my $rdn = _AuthorityKeyIdentifier($self); |
|
863
|
1
|
50
|
|
|
|
5
|
if ( !defined($rdn) ) { |
|
864
|
0
|
|
|
|
|
0
|
return (undef); # we do not have that extension |
|
865
|
|
|
|
|
|
|
} else { |
|
866
|
1
|
|
|
|
|
3
|
$rdn = $rdn->{'authorityCertIssuer'}[0]->{'directoryName'}; |
|
867
|
|
|
|
|
|
|
} |
|
868
|
1
|
|
|
|
|
4
|
$rdn->{'dn'} = []; |
|
869
|
1
|
|
|
|
|
2
|
my $dn = $rdn->{'dn'}; |
|
870
|
1
|
|
|
|
|
3
|
$rdn = $rdn->{'rdnSequence'}; |
|
871
|
1
|
|
|
|
|
2
|
foreach my $r ( @{$rdn} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
872
|
3
|
|
|
|
|
5
|
$i = @{$r}[0]; |
|
|
3
|
|
|
|
|
5
|
|
|
873
|
3
|
50
|
|
|
|
9
|
if ( $oid2attr{ $i->{'type'} } ) { |
|
874
|
3
|
|
|
|
|
7
|
$type = $oid2attr{ $i->{'type'} }; |
|
875
|
|
|
|
|
|
|
} else { |
|
876
|
0
|
|
|
|
|
0
|
$type = $i->{'type'}; |
|
877
|
|
|
|
|
|
|
} |
|
878
|
3
|
|
|
|
|
4
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
3
|
|
|
|
|
9
|
|
|
879
|
3
|
|
|
|
|
6
|
push @{$dn}, $type . "=" . $i->{'value'}->{ $key[0] }; |
|
|
3
|
|
|
|
|
10
|
|
|
880
|
|
|
|
|
|
|
} |
|
881
|
1
|
|
|
|
|
19
|
return $dn; |
|
882
|
|
|
|
|
|
|
} |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
sub _authcert_part { |
|
885
|
6
|
|
|
6
|
|
10
|
my $self = shift; |
|
886
|
6
|
|
|
|
|
9
|
my $oid = shift; |
|
887
|
6
|
|
|
|
|
13
|
my $rdn = _AuthorityKeyIdentifier($self); |
|
888
|
6
|
50
|
|
|
|
15
|
if ( !defined($rdn) ) { |
|
889
|
0
|
|
|
|
|
0
|
return (undef); # we do not have that extension |
|
890
|
|
|
|
|
|
|
} else { |
|
891
|
6
|
|
|
|
|
14
|
$rdn = $rdn->{'authorityCertIssuer'}[0]->{'directoryName'}->{'rdnSequence'}; |
|
892
|
|
|
|
|
|
|
} |
|
893
|
6
|
|
|
|
|
7
|
foreach my $r ( @{$rdn} ) { |
|
|
6
|
|
|
|
|
13
|
|
|
894
|
15
|
|
|
|
|
18
|
my $i = @{$r}[0]; |
|
|
15
|
|
|
|
|
25
|
|
|
895
|
15
|
100
|
|
|
|
32
|
if ( $i->{'type'} eq $oid ) { |
|
896
|
3
|
|
|
|
|
7
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
3
|
|
|
|
|
7
|
|
|
897
|
3
|
|
|
|
|
17
|
return $i->{'value'}->{ $key[0] }; |
|
898
|
|
|
|
|
|
|
} |
|
899
|
|
|
|
|
|
|
} |
|
900
|
3
|
|
|
|
|
14
|
return undef; |
|
901
|
|
|
|
|
|
|
} |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
=head2 authority_serial |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
Returns the authority's certificate serial number. |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
=cut back |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
sub authority_serial { |
|
910
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
911
|
0
|
|
|
|
|
0
|
return ( $self->_AuthorityKeyIdentifier )->{authorityCertSerialNumber}; |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=head2 key_identifier |
|
915
|
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
Returns the authority key identifier or undef if it is a rooted cert |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
=cut back |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
sub key_identifier { |
|
921
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
922
|
0
|
0
|
|
|
|
0
|
if ( defined $self->_AuthorityKeyIdentifier ) { return ( $self->_AuthorityKeyIdentifier )->{keyIdentifier}; } |
|
|
0
|
|
|
|
|
0
|
|
|
923
|
0
|
|
|
|
|
0
|
return undef; |
|
924
|
|
|
|
|
|
|
} |
|
925
|
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
=head2 authority_cn |
|
927
|
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
Returns the authority's ca. |
|
929
|
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
=cut back |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub authority_cn { |
|
933
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
934
|
1
|
|
|
|
|
5
|
return _authcert_part( $self, '2.5.4.3' ); |
|
935
|
|
|
|
|
|
|
} |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=head2 authority_country |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
Returns the authority's country. |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
=cut back |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
sub authority_country { |
|
944
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
945
|
1
|
|
|
|
|
3
|
return _authcert_part( $self, '2.5.4.6' ); |
|
946
|
|
|
|
|
|
|
} |
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=head2 authority_state |
|
949
|
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
Returns the authority's state. |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
=cut back |
|
953
|
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
sub authority_state { |
|
955
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
956
|
1
|
|
|
|
|
4
|
return _authcert_part( $self, '2.5.4.8' ); |
|
957
|
|
|
|
|
|
|
} |
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=head2 authority_locality |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
Returns the authority's locality. |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=cut back |
|
964
|
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
sub authority_locality { |
|
966
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
967
|
1
|
|
|
|
|
3
|
return _authcert_part( $self, '2.5.4.7' ); |
|
968
|
|
|
|
|
|
|
} |
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
=head2 authority_org |
|
971
|
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
Returns the authority's organization. |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
=cut back |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
sub authority_org { |
|
977
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
978
|
1
|
|
|
|
|
5
|
return _authcert_part( $self, '2.5.4.10' ); |
|
979
|
|
|
|
|
|
|
} |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
=head2 authority_email |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
Returns the authority's email. |
|
984
|
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
=cut back |
|
986
|
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
sub authority_email { |
|
988
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
989
|
1
|
|
|
|
|
3
|
return _authcert_part( $self, '1.2.840.113549.1.9.1' ); |
|
990
|
|
|
|
|
|
|
} |
|
991
|
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
=head2 CRLDistributionPoints |
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
Returns the CRL distribution points as an array of strings (with one value usually) |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=cut back |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub CRLDistributionPoints { |
|
999
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
1000
|
1
|
|
|
|
|
3
|
my $ext; |
|
1001
|
1
|
|
|
|
|
4
|
my $exts = $self->{'tbsCertificate'}->{'extensions'}; |
|
1002
|
1
|
50
|
|
|
|
4
|
if ( !defined $exts ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1003
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1004
|
1
|
|
|
|
|
2
|
foreach $ext ( @{$exts} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1005
|
2
|
100
|
|
|
|
7
|
if ( $ext->{'extnID'} eq '2.5.29.31' ) { #OID for cRLDistributionPoints |
|
1006
|
1
|
|
|
|
|
3
|
my $crlp = _init('cRLDistributionPoints'); # get a parser for this |
|
1007
|
1
|
|
|
|
|
5
|
my $points = $crlp->decode( $ext->{'extnValue'} ); # decode the value |
|
1008
|
1
|
|
|
|
|
321
|
$points = $points->[0]->{'distributionPoint'}->{'fullName'}; |
|
1009
|
1
|
50
|
|
|
|
4
|
if ( $crlp->error ) { |
|
1010
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $crlp->error; |
|
1011
|
0
|
|
|
|
|
0
|
return undef; |
|
1012
|
|
|
|
|
|
|
} |
|
1013
|
1
|
|
|
|
|
6
|
foreach my $name ( @{$points} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1014
|
1
|
|
|
|
|
2
|
push @{ $ext->{'crlpoints'} }, $name->{'uniformResourceIdentifier'}; |
|
|
1
|
|
|
|
|
4
|
|
|
1015
|
|
|
|
|
|
|
} |
|
1016
|
1
|
|
|
|
|
14
|
return $ext->{'crlpoints'}; |
|
1017
|
|
|
|
|
|
|
} |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
0
|
|
|
|
|
0
|
return undef; |
|
1020
|
|
|
|
|
|
|
} |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=head2 CRLDistributionPoints2 |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
Returns the CRL distribution points as an array of hashes (allowing for some variations) |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=cut back |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
# newer CRL |
|
1029
|
|
|
|
|
|
|
sub CRLDistributionPoints2 { |
|
1030
|
1
|
|
|
1
|
1
|
4
|
my $self = shift; |
|
1031
|
1
|
|
|
|
|
3
|
my %CDPs; |
|
1032
|
1
|
|
|
|
|
2
|
my $dp_cnt = 0; # this is a counter used to show which CDP a particular value is listed in |
|
1033
|
1
|
|
|
|
|
4
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1034
|
1
|
50
|
|
|
|
5
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1035
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1036
|
1
|
|
|
|
|
3
|
for my $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
1037
|
1
|
50
|
|
|
|
5
|
if ( $extension->{'extnID'} eq '2.5.29.31' ) { # OID for ARRAY of cRLDistributionPoints |
|
1038
|
1
|
|
|
|
|
3
|
my $parser = _init('cRLDistributionPoints'); # get a parser for CDPs |
|
1039
|
1
|
|
|
|
|
5
|
my $points = $parser->decode( $extension->{'extnValue'} ); # decode the values (returns an array) |
|
1040
|
1
|
|
|
|
|
1512
|
for my $each_dp ( @{$points} ) { # this loops through multiple "distributionPoint" values |
|
|
1
|
|
|
|
|
3
|
|
|
1041
|
1
|
|
|
|
|
3
|
$dp_cnt++; |
|
1042
|
1
|
|
|
|
|
3
|
for my $each_fullName ( @{ $each_dp->{'distributionPoint'}->{'fullName'} } ) |
|
|
1
|
|
|
|
|
4
|
|
|
1043
|
|
|
|
|
|
|
{ # this loops through multiple "fullName" values |
|
1044
|
2
|
100
|
|
|
|
10
|
if ( exists $each_fullName->{directoryName} ) { |
|
|
|
50
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
# found a rdnSequence |
|
1047
|
1
|
|
|
|
|
3
|
my $rdn = join ',', reverse @{ my_CRL_rdn( $each_fullName->{directoryName}->{rdnSequence} ) }; |
|
|
1
|
|
|
|
|
5
|
|
|
1048
|
1
|
|
|
|
|
4
|
push @{ $CDPs{$dp_cnt} }, "Directory Address: $rdn"; |
|
|
1
|
|
|
|
|
6
|
|
|
1049
|
|
|
|
|
|
|
} elsif ( exists $each_fullName->{uniformResourceIdentifier} ) { |
|
1050
|
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
# found a URI |
|
1052
|
1
|
|
|
|
|
2
|
push @{ $CDPs{$dp_cnt} }, "URL: " . $each_fullName->{uniformResourceIdentifier}; |
|
|
1
|
|
|
|
|
5
|
|
|
1053
|
|
|
|
|
|
|
} else { |
|
1054
|
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
# found some other type of CDP value |
|
1056
|
|
|
|
|
|
|
# return undef; |
|
1057
|
|
|
|
|
|
|
} |
|
1058
|
|
|
|
|
|
|
} |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
1
|
|
|
|
|
12
|
return %CDPs; |
|
1061
|
|
|
|
|
|
|
} |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
0
|
|
|
|
|
0
|
return undef; |
|
1064
|
|
|
|
|
|
|
} |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
sub my_CRL_rdn { |
|
1067
|
1
|
|
|
1
|
0
|
52
|
my $crl_rdn = shift; # this should be the passed in 'rdnSequence' array |
|
1068
|
1
|
|
|
|
|
4
|
my ( $i, $type ); |
|
1069
|
1
|
|
|
|
|
3
|
my $crl_dn = []; |
|
1070
|
1
|
|
|
|
|
3
|
for my $part ( @{$crl_rdn} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1071
|
6
|
|
|
|
|
10
|
$i = @{$part}[0]; |
|
|
6
|
|
|
|
|
37
|
|
|
1072
|
6
|
50
|
|
|
|
19
|
if ( $oid2attr{ $i->{'type'} } ) { |
|
1073
|
6
|
|
|
|
|
12
|
$type = $oid2attr{ $i->{'type'} }; |
|
1074
|
|
|
|
|
|
|
} else { |
|
1075
|
0
|
|
|
|
|
0
|
$type = $i->{'type'}; |
|
1076
|
|
|
|
|
|
|
} |
|
1077
|
6
|
|
|
|
|
9
|
my @key = keys( %{ $i->{'value'} } ); |
|
|
6
|
|
|
|
|
17
|
|
|
1078
|
6
|
|
|
|
|
9
|
push @{$crl_dn}, $type . "=" . $i->{'value'}->{ $key[0] }; |
|
|
6
|
|
|
|
|
17
|
|
|
1079
|
|
|
|
|
|
|
} |
|
1080
|
1
|
|
|
|
|
6
|
return $crl_dn; |
|
1081
|
|
|
|
|
|
|
} |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
=head2 CertificatePolicies |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
Returns the CertificatePolicies as an array of strings |
|
1086
|
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=cut back |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
# CertificatePolicies (another extension) |
|
1090
|
|
|
|
|
|
|
sub CertificatePolicies { |
|
1091
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
1092
|
0
|
|
|
|
|
0
|
my $extension; |
|
1093
|
0
|
|
|
|
|
0
|
my $CertPolicies = []; |
|
1094
|
0
|
|
|
|
|
0
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1095
|
0
|
0
|
|
|
|
0
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1096
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1097
|
0
|
|
|
|
|
0
|
for $extension ( @{$extensions} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1098
|
0
|
0
|
|
|
|
0
|
if ( $extension->{'extnID'} eq '2.5.29.32' ) { # OID for CertificatePolicies |
|
1099
|
0
|
|
|
|
|
0
|
my $parser = _init('CertificatePolicies'); # get a parser for this |
|
1100
|
0
|
|
|
|
|
0
|
my $policies = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1101
|
0
|
|
|
|
|
0
|
for my $policy ( @{$policies} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1102
|
0
|
|
|
|
|
0
|
for my $key ( keys %{$policy} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1103
|
0
|
|
|
|
|
0
|
push @{$CertPolicies}, "$key=" . $policy->{$key}; |
|
|
0
|
|
|
|
|
0
|
|
|
1104
|
|
|
|
|
|
|
} |
|
1105
|
|
|
|
|
|
|
} |
|
1106
|
0
|
|
|
|
|
0
|
return $CertPolicies; |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
|
|
|
|
|
|
} |
|
1109
|
0
|
|
|
|
|
0
|
return undef; |
|
1110
|
|
|
|
|
|
|
} |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=head2 EntrustVersionInfo |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
Returns the EntrustVersion as a string |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
print "Entrust Version: ", $decoded->EntrustVersion, "\n"; |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
Example Output: Entrust Version: V7.0 |
|
1119
|
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
=cut back |
|
1121
|
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
# EntrustVersion (another extension) |
|
1123
|
|
|
|
|
|
|
sub EntrustVersion { |
|
1124
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
|
1125
|
1
|
|
|
|
|
3
|
my $extension; |
|
1126
|
1
|
|
|
|
|
3
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1127
|
1
|
50
|
|
|
|
5
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1128
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1129
|
1
|
|
|
|
|
2
|
for $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
1130
|
7
|
100
|
|
|
|
15
|
if ( $extension->{'extnID'} eq '1.2.840.113533.7.65.0' ) { # OID for EntrustVersionInfo |
|
1131
|
1
|
|
|
|
|
5
|
my $parser = _init('EntrustVersionInfo'); # get a parser for this |
|
1132
|
1
|
|
|
|
|
5
|
my $entrust = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1133
|
1
|
|
|
|
|
167
|
return $entrust->{'entrustVers'}; |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
# not doing anything with the EntrustInfoFlags BIT STRING (yet) |
|
1136
|
|
|
|
|
|
|
# $entrust->{'entrustInfoFlags'} |
|
1137
|
|
|
|
|
|
|
} |
|
1138
|
|
|
|
|
|
|
} |
|
1139
|
0
|
|
|
|
|
0
|
return undef; |
|
1140
|
|
|
|
|
|
|
} |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=head2 SubjectDirectoryAttributes |
|
1143
|
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
Returns the SubjectDirectoryAttributes as an array of key = value pairs, to include a data type |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
print "Subject Directory Attributes: ", join( ', ' , @{ $decoded->SubjectDirectoryAttributes } ), "\n"; |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
Example Output: Subject Directory Attributes: 1.2.840.113533.7.68.29 = 7 (integer) |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
=cut back |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
# SubjectDirectoryAttributes (another extension) |
|
1153
|
|
|
|
|
|
|
sub SubjectDirectoryAttributes { |
|
1154
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
1155
|
0
|
|
|
|
|
0
|
my $extension; |
|
1156
|
0
|
|
|
|
|
0
|
my $attributes = []; |
|
1157
|
0
|
|
|
|
|
0
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1158
|
0
|
0
|
|
|
|
0
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1159
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1160
|
0
|
|
|
|
|
0
|
for $extension ( @{$extensions} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1161
|
0
|
0
|
|
|
|
0
|
if ( $extension->{'extnID'} eq '2.5.29.9' ) { # OID for SubjectDirectoryAttributes |
|
1162
|
0
|
|
|
|
|
0
|
my $parser = _init('SubjectDirectoryAttributes'); # get a parser for this |
|
1163
|
0
|
|
|
|
|
0
|
my $subject_dir_attrs = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1164
|
0
|
|
|
|
|
0
|
for my $type ( @{$subject_dir_attrs} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1165
|
0
|
|
|
|
|
0
|
for my $value ( @{ $type->{'values'} } ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1166
|
0
|
|
|
|
|
0
|
for my $key ( keys %{$value} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
1167
|
0
|
|
|
|
|
0
|
push @{$attributes}, $type->{'type'} . " = " . $value->{$key} . " ($key)"; |
|
|
0
|
|
|
|
|
0
|
|
|
1168
|
|
|
|
|
|
|
} |
|
1169
|
|
|
|
|
|
|
} |
|
1170
|
|
|
|
|
|
|
} |
|
1171
|
0
|
|
|
|
|
0
|
return $attributes; |
|
1172
|
|
|
|
|
|
|
} |
|
1173
|
|
|
|
|
|
|
} |
|
1174
|
0
|
|
|
|
|
0
|
return undef; |
|
1175
|
|
|
|
|
|
|
} |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
=head2 BasicConstraints |
|
1178
|
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
Returns the BasicConstraints as an array and the criticallity pre-pended. |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
=cut back |
|
1182
|
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
# BasicConstraints (another extension) |
|
1184
|
|
|
|
|
|
|
sub BasicConstraints { |
|
1185
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
1186
|
1
|
|
|
|
|
3
|
my $extension; |
|
1187
|
1
|
|
|
|
|
3
|
my $constraints = []; |
|
1188
|
1
|
|
|
|
|
3
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1189
|
1
|
50
|
|
|
|
5
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1190
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1191
|
1
|
|
|
|
|
3
|
for $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
1192
|
2
|
100
|
|
|
|
7
|
if ( $extension->{'extnID'} eq '2.5.29.19' ) { # OID for BasicConstraints |
|
1193
|
1
|
50
|
|
|
|
5
|
if ( $extension->{'critical'} ) { push @{$constraints}, "critical"; } # mark this as critical as appropriate |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
3
|
|
|
1194
|
1
|
|
|
|
|
5
|
my $parser = _init('BasicConstraints'); # get a parser for this |
|
1195
|
1
|
|
|
|
|
4
|
my $basic_constraints = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1196
|
1
|
|
|
|
|
177
|
for my $key ( keys %{$basic_constraints} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1197
|
1
|
|
|
|
|
3
|
push @{$constraints}, "$key = " . $basic_constraints->{$key}; |
|
|
1
|
|
|
|
|
5
|
|
|
1198
|
|
|
|
|
|
|
} |
|
1199
|
1
|
|
|
|
|
10
|
return $constraints; |
|
1200
|
|
|
|
|
|
|
} |
|
1201
|
|
|
|
|
|
|
} |
|
1202
|
0
|
|
|
|
|
0
|
return undef; |
|
1203
|
|
|
|
|
|
|
} |
|
1204
|
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
=head2 subject_keyidentifier |
|
1206
|
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
Returns the subject key identifier from the extensions. |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
=cut back |
|
1210
|
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
# subject_keyidentifier (another extension) |
|
1212
|
|
|
|
|
|
|
sub subject_keyidentifier { |
|
1213
|
1
|
|
|
1
|
1
|
553
|
my $self = shift; |
|
1214
|
1
|
|
|
|
|
5
|
return $self->_SubjectKeyIdentifier; |
|
1215
|
|
|
|
|
|
|
} |
|
1216
|
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
# _SubjectKeyIdentifier (another extension) |
|
1218
|
|
|
|
|
|
|
sub _SubjectKeyIdentifier { |
|
1219
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
|
1220
|
1
|
|
|
|
|
4
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1221
|
1
|
50
|
|
|
|
4
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1222
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1223
|
1
|
50
|
|
|
|
3
|
if ( defined $self->{'tbsCertificate'}{'SubjectKeyIdentifier'} ) { |
|
1224
|
0
|
|
|
|
|
0
|
return ( $self->{'tbsCertificate'}{'SubjectKeyIdentifier'} ); |
|
1225
|
|
|
|
|
|
|
} |
|
1226
|
1
|
|
|
|
|
3
|
for my $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
3
|
|
|
1227
|
4
|
100
|
|
|
|
11
|
if ( $extension->{'extnID'} eq '2.5.29.14' ) { # OID for SubjectKeyIdentifier |
|
1228
|
1
|
|
|
|
|
4
|
my $parser = _init('SubjectKeyIdentifier'); # get a parser for this |
|
1229
|
1
|
|
|
|
|
5
|
$self->{'tbsCertificate'}{'SubjectKeyIdentifier'} = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1230
|
1
|
50
|
|
|
|
81
|
if ( $parser->error ) { |
|
1231
|
0
|
|
|
|
|
0
|
$self->{"_error"} = $parser->error; |
|
1232
|
0
|
|
|
|
|
0
|
return undef; |
|
1233
|
|
|
|
|
|
|
} |
|
1234
|
1
|
|
|
|
|
12
|
return $self->{'tbsCertificate'}{'SubjectKeyIdentifier'}; |
|
1235
|
|
|
|
|
|
|
} |
|
1236
|
|
|
|
|
|
|
} |
|
1237
|
0
|
|
|
|
|
0
|
return undef; |
|
1238
|
|
|
|
|
|
|
} |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
=head2 SubjectInfoAccess |
|
1241
|
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
Returns the SubjectInfoAccess as an array of hashes with key=value pairs. |
|
1243
|
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
print "Subject Info Access: "; |
|
1245
|
|
|
|
|
|
|
if ( defined $decoded->SubjectInfoAccess ) { |
|
1246
|
|
|
|
|
|
|
my %SIA = $decoded->SubjectInfoAccess; |
|
1247
|
|
|
|
|
|
|
for my $key ( keys %SIA ) { |
|
1248
|
|
|
|
|
|
|
print "\n\t$key: \n\t"; |
|
1249
|
|
|
|
|
|
|
print join( "\n\t" , @{ $SIA{$key} } ), "\n"; |
|
1250
|
|
|
|
|
|
|
} |
|
1251
|
|
|
|
|
|
|
} else { print "\n" } |
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
Example Output: |
|
1254
|
|
|
|
|
|
|
Subject Info Access: |
|
1255
|
|
|
|
|
|
|
1.3.6.1.5.5.7.48.5: |
|
1256
|
|
|
|
|
|
|
uniformResourceIdentifier = http://pki.treas.gov/root_sia.p7c |
|
1257
|
|
|
|
|
|
|
uniformResourceIdentifier = ldap://ldap.treas.gov/ou=US%20Treasury%20Root%20CA,ou=Certification%20Authorities,ou=Department%20of%20the%20Treasury,o=U.S.%20Government,c=US?cACertificate;binary,crossCertificatePair;binary |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
=cut back |
|
1260
|
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
# SubjectInfoAccess (another extension) |
|
1262
|
|
|
|
|
|
|
sub SubjectInfoAccess { |
|
1263
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
1264
|
1
|
|
|
|
|
3
|
my $extension; |
|
1265
|
|
|
|
|
|
|
my %SIA; |
|
1266
|
1
|
|
|
|
|
5
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1267
|
1
|
50
|
|
|
|
5
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1268
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1269
|
1
|
|
|
|
|
3
|
for $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
5
|
|
|
1270
|
3
|
100
|
|
|
|
10
|
if ( $extension->{'extnID'} eq '1.3.6.1.5.5.7.1.11' ) { # OID for SubjectInfoAccess |
|
1271
|
1
|
|
|
|
|
5
|
my $parser = _init('SubjectInfoAccessSyntax'); # get a parser for this |
|
1272
|
1
|
|
|
|
|
5
|
my $subject_info_access = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1273
|
1
|
|
|
|
|
430
|
for my $sia ( @{$subject_info_access} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1274
|
2
|
|
|
|
|
5
|
for my $key ( keys %{ $sia->{'accessLocation'} } ) { |
|
|
2
|
|
|
|
|
7
|
|
|
1275
|
2
|
|
|
|
|
4
|
push @{ $SIA{ $sia->{'accessMethod'} } }, "$key = " . $sia->{'accessLocation'}{$key}; |
|
|
2
|
|
|
|
|
11
|
|
|
1276
|
|
|
|
|
|
|
} |
|
1277
|
|
|
|
|
|
|
} |
|
1278
|
1
|
|
|
|
|
12
|
return %SIA; |
|
1279
|
|
|
|
|
|
|
} |
|
1280
|
|
|
|
|
|
|
} |
|
1281
|
0
|
|
|
|
|
0
|
return undef; |
|
1282
|
|
|
|
|
|
|
} |
|
1283
|
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=head2 PGPExtension |
|
1286
|
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
Returns the creation timestamp of the corresponding OpenPGP key. |
|
1288
|
|
|
|
|
|
|
(see http://www.imc.org/ietf-openpgp/mail-archive/msg05320.html) |
|
1289
|
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
print "PGPExtension: "; |
|
1291
|
|
|
|
|
|
|
if ( defined $decoded->PGPExtension ) { |
|
1292
|
|
|
|
|
|
|
my $creationtime = $decoded->PGPExtension; |
|
1293
|
|
|
|
|
|
|
printf "\n\tcorresponding OpenPGP Creation Time: ", $creationtime, "\n"; |
|
1294
|
|
|
|
|
|
|
} |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
Example Output: |
|
1297
|
|
|
|
|
|
|
PGPExtension: |
|
1298
|
|
|
|
|
|
|
whatever |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
=cut back |
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
# PGPExtension (another extension) |
|
1303
|
|
|
|
|
|
|
sub PGPExtension { |
|
1304
|
1
|
|
|
1
|
1
|
4
|
my $self = shift; |
|
1305
|
1
|
|
|
|
|
3
|
my $extension; |
|
1306
|
1
|
|
|
|
|
5
|
my $extensions = $self->{'tbsCertificate'}->{'extensions'}; |
|
1307
|
1
|
50
|
|
|
|
11
|
if ( !defined $extensions ) { return undef; } |
|
|
0
|
|
|
|
|
0
|
|
|
1308
|
|
|
|
|
|
|
; # no extensions in certificate |
|
1309
|
1
|
|
|
|
|
3
|
for $extension ( @{$extensions} ) { |
|
|
1
|
|
|
|
|
4
|
|
|
1310
|
6
|
100
|
|
|
|
14
|
if ( $extension->{'extnID'} eq '1.3.6.1.4.1.3401.8.1.1' ) { # OID for PGPExtension |
|
1311
|
1
|
|
|
|
|
3
|
my $parser = _init('PGPExtension'); # get a parser for this |
|
1312
|
1
|
|
|
|
|
4
|
my $pgpextension = $parser->decode( $extension->{'extnValue'} ); # decode the value |
|
1313
|
1
|
50
|
|
|
|
233
|
if ($pgpextension->{version} != 0) { |
|
1314
|
0
|
|
|
|
|
0
|
$self->{"_error"} = sprintf("got PGPExtension version %d. We only know how to deal with v1 (0)", $pgpextension->{version}); |
|
1315
|
|
|
|
|
|
|
} else { |
|
1316
|
1
|
|
|
|
|
4
|
foreach my $timetype ('generalTime', 'utcTime') { |
|
1317
|
|
|
|
|
|
|
return $pgpextension->{keyCreation}->{$timetype} |
|
1318
|
1
|
50
|
|
|
|
10
|
if exists $pgpextension->{keyCreation}->{$timetype}; |
|
1319
|
|
|
|
|
|
|
} |
|
1320
|
|
|
|
|
|
|
} |
|
1321
|
|
|
|
|
|
|
} |
|
1322
|
|
|
|
|
|
|
} |
|
1323
|
0
|
|
|
|
|
0
|
return undef; |
|
1324
|
|
|
|
|
|
|
} |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
####################################################################### |
|
1327
|
|
|
|
|
|
|
# internal functions |
|
1328
|
|
|
|
|
|
|
####################################################################### |
|
1329
|
|
|
|
|
|
|
sub _init { |
|
1330
|
19
|
|
|
19
|
|
34
|
my $what = shift; |
|
1331
|
19
|
100
|
66
|
|
|
94
|
if ( ( !defined $what ) || ( '' eq $what ) ) { $what = 'Certificate' } |
|
|
2
|
|
|
|
|
4
|
|
|
1332
|
19
|
100
|
|
|
|
45
|
if ( !defined $asn ) { |
|
1333
|
1
|
|
|
|
|
7
|
$asn = Convert::ASN1->new; |
|
1334
|
1
|
|
|
|
|
46
|
$asn->prepare(<
|
|
1335
|
|
|
|
|
|
|
-- ASN.1 from RFC2459 and X.509(2001) |
|
1336
|
|
|
|
|
|
|
-- Adapted for use with Convert::ASN1 |
|
1337
|
|
|
|
|
|
|
-- Id: x509decode,v 1.1 2002/02/10 16:41:28 gbarr Exp |
|
1338
|
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
-- attribute data types -- |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
Attribute ::= SEQUENCE { |
|
1342
|
|
|
|
|
|
|
type AttributeType, |
|
1343
|
|
|
|
|
|
|
values SET OF AttributeValue |
|
1344
|
|
|
|
|
|
|
-- at least one value is required -- |
|
1345
|
|
|
|
|
|
|
} |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
AttributeType ::= OBJECT IDENTIFIER |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
AttributeValue ::= DirectoryString --ANY |
|
1350
|
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
AttributeTypeAndValue ::= SEQUENCE { |
|
1352
|
|
|
|
|
|
|
type AttributeType, |
|
1353
|
|
|
|
|
|
|
value AttributeValue |
|
1354
|
|
|
|
|
|
|
} |
|
1355
|
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
-- naming data types -- |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
Name ::= CHOICE { -- only one possibility for now |
|
1360
|
|
|
|
|
|
|
rdnSequence RDNSequence |
|
1361
|
|
|
|
|
|
|
} |
|
1362
|
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName |
|
1364
|
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
DistinguishedName ::= RDNSequence |
|
1366
|
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
RelativeDistinguishedName ::= |
|
1368
|
|
|
|
|
|
|
SET OF AttributeTypeAndValue --SET SIZE (1 .. MAX) OF |
|
1369
|
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
-- Directory string type -- |
|
1372
|
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
DirectoryString ::= CHOICE { |
|
1374
|
|
|
|
|
|
|
teletexString TeletexString, --(SIZE (1..MAX)), |
|
1375
|
|
|
|
|
|
|
printableString PrintableString, --(SIZE (1..MAX)), |
|
1376
|
|
|
|
|
|
|
bmpString BMPString, --(SIZE (1..MAX)), |
|
1377
|
|
|
|
|
|
|
universalString UniversalString, --(SIZE (1..MAX)), |
|
1378
|
|
|
|
|
|
|
utf8String UTF8String, --(SIZE (1..MAX)), |
|
1379
|
|
|
|
|
|
|
ia5String IA5String, --added for EmailAddress, |
|
1380
|
|
|
|
|
|
|
integer INTEGER |
|
1381
|
|
|
|
|
|
|
} |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
-- certificate and CRL specific structures begin here |
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
Certificate ::= SEQUENCE { |
|
1387
|
|
|
|
|
|
|
tbsCertificate TBSCertificate, |
|
1388
|
|
|
|
|
|
|
signatureAlgorithm AlgorithmIdentifier, |
|
1389
|
|
|
|
|
|
|
signature BIT STRING |
|
1390
|
|
|
|
|
|
|
} |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
TBSCertificate ::= SEQUENCE { |
|
1393
|
|
|
|
|
|
|
version [0] EXPLICIT Version OPTIONAL, --DEFAULT v1 |
|
1394
|
|
|
|
|
|
|
serialNumber CertificateSerialNumber, |
|
1395
|
|
|
|
|
|
|
signature AlgorithmIdentifier, |
|
1396
|
|
|
|
|
|
|
issuer Name, |
|
1397
|
|
|
|
|
|
|
validity Validity, |
|
1398
|
|
|
|
|
|
|
subject Name, |
|
1399
|
|
|
|
|
|
|
subjectPublicKeyInfo SubjectPublicKeyInfo, |
|
1400
|
|
|
|
|
|
|
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, |
|
1401
|
|
|
|
|
|
|
-- If present, version shall be v2 or v3 |
|
1402
|
|
|
|
|
|
|
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, |
|
1403
|
|
|
|
|
|
|
-- If present, version shall be v2 or v3 |
|
1404
|
|
|
|
|
|
|
extensions [3] EXPLICIT Extensions OPTIONAL |
|
1405
|
|
|
|
|
|
|
-- If present, version shall be v3 |
|
1406
|
|
|
|
|
|
|
} |
|
1407
|
|
|
|
|
|
|
|
|
1408
|
|
|
|
|
|
|
Version ::= INTEGER --{ v1(0), v2(1), v3(2) } |
|
1409
|
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
CertificateSerialNumber ::= INTEGER |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
Validity ::= SEQUENCE { |
|
1413
|
|
|
|
|
|
|
notBefore Time, |
|
1414
|
|
|
|
|
|
|
notAfter Time |
|
1415
|
|
|
|
|
|
|
} |
|
1416
|
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
Time ::= CHOICE { |
|
1418
|
|
|
|
|
|
|
utcTime UTCTime, |
|
1419
|
|
|
|
|
|
|
generalTime GeneralizedTime |
|
1420
|
|
|
|
|
|
|
} |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
UniqueIdentifier ::= BIT STRING |
|
1423
|
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
SubjectPublicKeyInfo ::= SEQUENCE { |
|
1425
|
|
|
|
|
|
|
algorithm AlgorithmIdentifier, |
|
1426
|
|
|
|
|
|
|
subjectPublicKey BIT STRING |
|
1427
|
|
|
|
|
|
|
} |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
RSAPubKeyInfo ::= SEQUENCE { |
|
1431
|
|
|
|
|
|
|
modulus INTEGER, |
|
1432
|
|
|
|
|
|
|
exponent INTEGER |
|
1433
|
|
|
|
|
|
|
} |
|
1434
|
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
Extensions ::= SEQUENCE OF Extension --SIZE (1..MAX) OF Extension |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
Extension ::= SEQUENCE { |
|
1438
|
|
|
|
|
|
|
extnID OBJECT IDENTIFIER, |
|
1439
|
|
|
|
|
|
|
critical BOOLEAN OPTIONAL, --DEFAULT FALSE, |
|
1440
|
|
|
|
|
|
|
extnValue OCTET STRING |
|
1441
|
|
|
|
|
|
|
} |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
AlgorithmIdentifier ::= SEQUENCE { |
|
1444
|
|
|
|
|
|
|
algorithm OBJECT IDENTIFIER, |
|
1445
|
|
|
|
|
|
|
parameters ANY OPTIONAL |
|
1446
|
|
|
|
|
|
|
} |
|
1447
|
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
--extensions |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
AuthorityKeyIdentifier ::= SEQUENCE { |
|
1452
|
|
|
|
|
|
|
keyIdentifier [0] KeyIdentifier OPTIONAL, |
|
1453
|
|
|
|
|
|
|
authorityCertIssuer [1] GeneralNames OPTIONAL, |
|
1454
|
|
|
|
|
|
|
authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } |
|
1455
|
|
|
|
|
|
|
-- authorityCertIssuer and authorityCertSerialNumber shall both |
|
1456
|
|
|
|
|
|
|
-- be present or both be absent |
|
1457
|
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
KeyIdentifier ::= OCTET STRING |
|
1459
|
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
SubjectKeyIdentifier ::= KeyIdentifier |
|
1461
|
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
-- key usage extension OID and syntax |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
-- id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } |
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
KeyUsage ::= BIT STRING --{ |
|
1467
|
|
|
|
|
|
|
-- digitalSignature (0), |
|
1468
|
|
|
|
|
|
|
-- nonRepudiation (1), |
|
1469
|
|
|
|
|
|
|
-- keyEncipherment (2), |
|
1470
|
|
|
|
|
|
|
-- dataEncipherment (3), |
|
1471
|
|
|
|
|
|
|
-- keyAgreement (4), |
|
1472
|
|
|
|
|
|
|
-- keyCertSign (5), |
|
1473
|
|
|
|
|
|
|
-- cRLSign (6), |
|
1474
|
|
|
|
|
|
|
-- encipherOnly (7), |
|
1475
|
|
|
|
|
|
|
-- decipherOnly (8) } |
|
1476
|
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
-- private key usage period extension OID and syntax |
|
1479
|
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
-- id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-ce 16 } |
|
1481
|
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
PrivateKeyUsagePeriod ::= SEQUENCE { |
|
1483
|
|
|
|
|
|
|
notBefore [0] GeneralizedTime OPTIONAL, |
|
1484
|
|
|
|
|
|
|
notAfter [1] GeneralizedTime OPTIONAL } |
|
1485
|
|
|
|
|
|
|
-- either notBefore or notAfter shall be present |
|
1486
|
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
-- certificate policies extension OID and syntax |
|
1488
|
|
|
|
|
|
|
-- id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } |
|
1489
|
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
CertificatePolicies ::= SEQUENCE OF PolicyInformation |
|
1491
|
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
PolicyInformation ::= SEQUENCE { |
|
1493
|
|
|
|
|
|
|
policyIdentifier CertPolicyId, |
|
1494
|
|
|
|
|
|
|
policyQualifiers SEQUENCE OF |
|
1495
|
|
|
|
|
|
|
PolicyQualifierInfo OPTIONAL } |
|
1496
|
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
CertPolicyId ::= OBJECT IDENTIFIER |
|
1498
|
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
PolicyQualifierInfo ::= SEQUENCE { |
|
1500
|
|
|
|
|
|
|
policyQualifierId PolicyQualifierId, |
|
1501
|
|
|
|
|
|
|
qualifier ANY } --DEFINED BY policyQualifierId } |
|
1502
|
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
-- Implementations that recognize additional policy qualifiers shall |
|
1504
|
|
|
|
|
|
|
-- augment the following definition for PolicyQualifierId |
|
1505
|
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
PolicyQualifierId ::= |
|
1507
|
|
|
|
|
|
|
OBJECT IDENTIFIER --( id-qt-cps | id-qt-unotice ) |
|
1508
|
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
-- CPS pointer qualifier |
|
1510
|
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
CPSuri ::= IA5String |
|
1512
|
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
-- user notice qualifier |
|
1514
|
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
UserNotice ::= SEQUENCE { |
|
1516
|
|
|
|
|
|
|
noticeRef NoticeReference OPTIONAL, |
|
1517
|
|
|
|
|
|
|
explicitText DisplayText OPTIONAL} |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
NoticeReference ::= SEQUENCE { |
|
1520
|
|
|
|
|
|
|
organization DisplayText, |
|
1521
|
|
|
|
|
|
|
noticeNumbers SEQUENCE OF INTEGER } |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
DisplayText ::= CHOICE { |
|
1524
|
|
|
|
|
|
|
visibleString VisibleString , |
|
1525
|
|
|
|
|
|
|
bmpString BMPString , |
|
1526
|
|
|
|
|
|
|
utf8String UTF8String } |
|
1527
|
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
-- policy mapping extension OID and syntax |
|
1530
|
|
|
|
|
|
|
-- id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } |
|
1531
|
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
PolicyMappings ::= SEQUENCE OF SEQUENCE { |
|
1533
|
|
|
|
|
|
|
issuerDomainPolicy CertPolicyId, |
|
1534
|
|
|
|
|
|
|
subjectDomainPolicy CertPolicyId } |
|
1535
|
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
-- subject alternative name extension OID and syntax |
|
1538
|
|
|
|
|
|
|
-- id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } |
|
1539
|
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
SubjectAltName ::= GeneralNames |
|
1541
|
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
GeneralNames ::= SEQUENCE OF GeneralName |
|
1543
|
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
GeneralName ::= CHOICE { |
|
1545
|
|
|
|
|
|
|
otherName [0] AnotherName, |
|
1546
|
|
|
|
|
|
|
rfc822Name [1] IA5String, |
|
1547
|
|
|
|
|
|
|
dNSName [2] IA5String, |
|
1548
|
|
|
|
|
|
|
x400Address [3] ANY, --ORAddress, |
|
1549
|
|
|
|
|
|
|
directoryName [4] Name, |
|
1550
|
|
|
|
|
|
|
ediPartyName [5] EDIPartyName, |
|
1551
|
|
|
|
|
|
|
uniformResourceIdentifier [6] IA5String, |
|
1552
|
|
|
|
|
|
|
iPAddress [7] OCTET STRING, |
|
1553
|
|
|
|
|
|
|
registeredID [8] OBJECT IDENTIFIER } |
|
1554
|
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
EntrustVersionInfo ::= SEQUENCE { |
|
1556
|
|
|
|
|
|
|
entrustVers GeneralString, |
|
1557
|
|
|
|
|
|
|
entrustInfoFlags EntrustInfoFlags } |
|
1558
|
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
EntrustInfoFlags::= BIT STRING --{ |
|
1560
|
|
|
|
|
|
|
-- keyUpdateAllowed |
|
1561
|
|
|
|
|
|
|
-- newExtensions (1), -- not used |
|
1562
|
|
|
|
|
|
|
-- pKIXCertificate (2) } -- certificate created by pkix |
|
1563
|
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as |
|
1565
|
|
|
|
|
|
|
-- TYPE-IDENTIFIER is not supported in the 88 ASN.1 syntax |
|
1566
|
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
AnotherName ::= SEQUENCE { |
|
1568
|
|
|
|
|
|
|
type OBJECT IDENTIFIER, |
|
1569
|
|
|
|
|
|
|
value [0] EXPLICIT ANY } --DEFINED BY type-id } |
|
1570
|
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
EDIPartyName ::= SEQUENCE { |
|
1572
|
|
|
|
|
|
|
nameAssigner [0] DirectoryString OPTIONAL, |
|
1573
|
|
|
|
|
|
|
partyName [1] DirectoryString } |
|
1574
|
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
-- issuer alternative name extension OID and syntax |
|
1577
|
|
|
|
|
|
|
-- id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } |
|
1578
|
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
IssuerAltName ::= GeneralNames |
|
1580
|
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
-- id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } |
|
1583
|
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
SubjectDirectoryAttributes ::= SEQUENCE OF Attribute |
|
1585
|
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
-- basic constraints extension OID and syntax |
|
1588
|
|
|
|
|
|
|
-- id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } |
|
1589
|
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
BasicConstraints ::= SEQUENCE { |
|
1591
|
|
|
|
|
|
|
cA BOOLEAN OPTIONAL, --DEFAULT FALSE, |
|
1592
|
|
|
|
|
|
|
pathLenConstraint INTEGER OPTIONAL } |
|
1593
|
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
-- name constraints extension OID and syntax |
|
1596
|
|
|
|
|
|
|
-- id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } |
|
1597
|
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
NameConstraints ::= SEQUENCE { |
|
1599
|
|
|
|
|
|
|
permittedSubtrees [0] GeneralSubtrees OPTIONAL, |
|
1600
|
|
|
|
|
|
|
excludedSubtrees [1] GeneralSubtrees OPTIONAL } |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
GeneralSubtrees ::= SEQUENCE OF GeneralSubtree |
|
1603
|
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
GeneralSubtree ::= SEQUENCE { |
|
1605
|
|
|
|
|
|
|
base GeneralName, |
|
1606
|
|
|
|
|
|
|
minimum [0] BaseDistance OPTIONAL, --DEFAULT 0, |
|
1607
|
|
|
|
|
|
|
maximum [1] BaseDistance OPTIONAL } |
|
1608
|
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
BaseDistance ::= INTEGER |
|
1610
|
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
-- policy constraints extension OID and syntax |
|
1613
|
|
|
|
|
|
|
-- id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } |
|
1614
|
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
PolicyConstraints ::= SEQUENCE { |
|
1616
|
|
|
|
|
|
|
requireExplicitPolicy [0] SkipCerts OPTIONAL, |
|
1617
|
|
|
|
|
|
|
inhibitPolicyMapping [1] SkipCerts OPTIONAL } |
|
1618
|
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
SkipCerts ::= INTEGER |
|
1620
|
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
-- CRL distribution points extension OID and syntax |
|
1623
|
|
|
|
|
|
|
-- id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31} |
|
1624
|
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
cRLDistributionPoints ::= SEQUENCE OF DistributionPoint |
|
1626
|
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
DistributionPoint ::= SEQUENCE { |
|
1628
|
|
|
|
|
|
|
distributionPoint [0] DistributionPointName OPTIONAL, |
|
1629
|
|
|
|
|
|
|
reasons [1] ReasonFlags OPTIONAL, |
|
1630
|
|
|
|
|
|
|
cRLIssuer [2] GeneralNames OPTIONAL } |
|
1631
|
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
DistributionPointName ::= CHOICE { |
|
1633
|
|
|
|
|
|
|
fullName [0] GeneralNames, |
|
1634
|
|
|
|
|
|
|
nameRelativeToCRLIssuer [1] RelativeDistinguishedName } |
|
1635
|
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
ReasonFlags ::= BIT STRING --{ |
|
1637
|
|
|
|
|
|
|
-- unused (0), |
|
1638
|
|
|
|
|
|
|
-- keyCompromise (1), |
|
1639
|
|
|
|
|
|
|
-- cACompromise (2), |
|
1640
|
|
|
|
|
|
|
-- affiliationChanged (3), |
|
1641
|
|
|
|
|
|
|
-- superseded (4), |
|
1642
|
|
|
|
|
|
|
-- cessationOfOperation (5), |
|
1643
|
|
|
|
|
|
|
-- certificateHold (6), |
|
1644
|
|
|
|
|
|
|
-- privilegeWithdrawn (7), |
|
1645
|
|
|
|
|
|
|
-- aACompromise (8) } |
|
1646
|
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
-- extended key usage extension OID and syntax |
|
1649
|
|
|
|
|
|
|
-- id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37} |
|
1650
|
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
ExtKeyUsageSyntax ::= SEQUENCE OF KeyPurposeId |
|
1652
|
|
|
|
|
|
|
|
|
1653
|
|
|
|
|
|
|
KeyPurposeId ::= OBJECT IDENTIFIER |
|
1654
|
|
|
|
|
|
|
|
|
1655
|
|
|
|
|
|
|
-- extended key purpose OIDs |
|
1656
|
|
|
|
|
|
|
-- id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } |
|
1657
|
|
|
|
|
|
|
-- id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } |
|
1658
|
|
|
|
|
|
|
-- id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } |
|
1659
|
|
|
|
|
|
|
-- id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } |
|
1660
|
|
|
|
|
|
|
-- id-kp-ipsecEndSystem OBJECT IDENTIFIER ::= { id-kp 5 } |
|
1661
|
|
|
|
|
|
|
-- id-kp-ipsecTunnel OBJECT IDENTIFIER ::= { id-kp 6 } |
|
1662
|
|
|
|
|
|
|
-- id-kp-ipsecUser OBJECT IDENTIFIER ::= { id-kp 7 } |
|
1663
|
|
|
|
|
|
|
-- id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } |
|
1664
|
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
-- authority info access |
|
1666
|
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
-- id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } |
|
1668
|
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
AuthorityInfoAccessSyntax ::= |
|
1670
|
|
|
|
|
|
|
SEQUENCE OF AccessDescription --SIZE (1..MAX) OF AccessDescription |
|
1671
|
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
AccessDescription ::= SEQUENCE { |
|
1673
|
|
|
|
|
|
|
accessMethod OBJECT IDENTIFIER, |
|
1674
|
|
|
|
|
|
|
accessLocation GeneralName } |
|
1675
|
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
-- subject info access |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
-- id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 } |
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
SubjectInfoAccessSyntax ::= |
|
1681
|
|
|
|
|
|
|
SEQUENCE OF AccessDescription --SIZE (1..MAX) OF AccessDescription |
|
1682
|
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
-- pgp creation time |
|
1684
|
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
PGPExtension ::= SEQUENCE { |
|
1686
|
|
|
|
|
|
|
version Version, -- DEFAULT v1(0) |
|
1687
|
|
|
|
|
|
|
keyCreation Time |
|
1688
|
|
|
|
|
|
|
} |
|
1689
|
|
|
|
|
|
|
ASN1 |
|
1690
|
|
|
|
|
|
|
} |
|
1691
|
19
|
|
|
|
|
61314
|
my $self = $asn->find($what); |
|
1692
|
19
|
|
|
|
|
305
|
return $self; |
|
1693
|
|
|
|
|
|
|
} |
|
1694
|
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
1696
|
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
See the examples of C and the Mailing List. |
|
1698
|
|
|
|
|
|
|
An example on how to load certificates can be found in F. |
|
1699
|
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
1701
|
|
|
|
|
|
|
|
|
1702
|
|
|
|
|
|
|
This module is based on the x509decode script, which was contributed to |
|
1703
|
|
|
|
|
|
|
Convert::ASN1 in 2002 by Norbert Klasen. |
|
1704
|
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
=head1 AUTHORS |
|
1706
|
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
Mike Jackson , |
|
1708
|
|
|
|
|
|
|
Alexander Jung , |
|
1709
|
|
|
|
|
|
|
Duncan Segrest |
|
1710
|
|
|
|
|
|
|
Oliver Welter |
|
1711
|
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
1713
|
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
Copyright (c) 2005 Mike Jackson . |
|
1715
|
|
|
|
|
|
|
Copyright (c) 2001-2002 Norbert Klasen, DAASI International GmbH. |
|
1716
|
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
All rights reserved. This program is free software; you can redistribute |
|
1718
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
|
1719
|
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
=cut |
|
1721
|
|
|
|
|
|
|
1; |
|
1722
|
|
|
|
|
|
|
__END__ |