1#
2# Crypt::PKCS10
3#
4# ABSTRACT: parse PKCS #10 certificate requests
5#
6# This software is copyright (c) 2014 by Gideon Knocke.
7# Copyright (c) 2016 Gideon Knocke, Timothe Litt
8#
9# See LICENSE for details.
10#
11
12package Crypt::PKCS10;
13
14use strict;
15use warnings;
16use Carp;
17
18use overload( q("") => 'as_string' );
19
20use Convert::ASN1( qw/:tag :const/ );
21use Encode ();
22use MIME::Base64;
23use Scalar::Util ();
24
25our $VERSION = '2.002';
26
27my $apiVersion = undef;  # 0 for compatibility.  1 for prefered
28my $error;
29
30# N.B. Names are exposed in the API.
31#      %shortnames follows & depends on (some) values.
32# When adding OIDs, re-generate the documentation (see "for MAINTAINER" below)
33#
34# New OIDs don't need the [ ] syntax, which is [ prefered name, deprecated name ]
35# Some of the deprecated names are used in the ASN.1 definition. and in the $self
36# structure, which unfortunately is exposed with the attributes() method.
37# Dealing with the deprecated names causes some messy code.
38
39my %oids = (
40    '2.5.4.6'                       => 'countryName',
41    '2.5.4.8'                       => 'stateOrProvinceName',
42    '2.5.4.10'                      => 'organizationName',
43    '2.5.4.11'                      => 'organizationalUnitName',
44    '2.5.4.3'                       => 'commonName',
45    '1.2.840.113549.1.9.1'          => 'emailAddress',
46    '1.2.840.113549.1.9.2'          => 'unstructuredName',
47    '1.2.840.113549.1.9.7'          => 'challengePassword',
48    '1.2.840.113549.1.1.1'          => [ 'rsaEncryption', 'RSA encryption' ],
49    '1.2.840.113549.1.1.5'          => [ 'sha1WithRSAEncryption', 'SHA1 with RSA encryption' ],
50    '1.2.840.113549.1.1.4'          => [ 'md5WithRSAEncryption', 'MD5 with RSA encryption' ],
51    '1.2.840.113549.1.9.14'         => 'extensionRequest',
52    '1.3.6.1.4.1.311.13.2.3'        => 'OS_Version',                   # Microsoft
53    '1.3.6.1.4.1.311.13.2.2'        => 'EnrollmentCSP',                # Microsoft
54    '1.3.6.1.4.1.311.21.20'         => 'ClientInformation',            # Microsoft REQUEST_CLIENT_INFO
55    '1.3.6.1.4.1.311.21.7'          => 'certificateTemplate',          # Microsoft
56    '2.5.29.37'                     => [ 'extKeyUsage', 'EnhancedKeyUsage' ],
57    '2.5.29.15'                     => [ 'keyUsage', 'KeyUsage' ],
58    '1.3.6.1.4.1.311.21.10'         => 'ApplicationCertPolicies',      # Microsoft APPLICATION_CERT_POLICIES
59    '2.5.29.14'                     => [ 'subjectKeyIdentifier', 'SubjectKeyIdentifier' ],
60    '2.5.29.17'                     => 'subjectAltName',
61    '1.3.6.1.4.1.311.20.2'          => 'certificateTemplateName',      # Microsoft
62    '2.16.840.1.113730.1.1'         => 'netscapeCertType',
63    '2.16.840.1.113730.1.2'         => 'netscapeBaseUrl',
64    '2.16.840.1.113730.1.4'         => 'netscapeCaRevocationUrl',
65    '2.16.840.1.113730.1.7'         => 'netscapeCertRenewalUrl',
66    '2.16.840.1.113730.1.8'         => 'netscapeCaPolicyUrl',
67    '2.16.840.1.113730.1.12'        => 'netscapeSSLServerName',
68    '2.16.840.1.113730.1.13'        => 'netscapeComment',
69
70    #untested
71    '2.5.29.19'                     => [ 'basicConstraints', 'Basic Constraints' ],
72    '1.2.840.10040.4.1'             => [ 'dsa', 'DSA' ],
73    '1.2.840.10040.4.3'             => [ 'dsaWithSha1', 'DSA with SHA1' ],
74    '1.2.840.10045.2.1'             => 'ecPublicKey',
75    '1.2.840.10045.4.3.1'           => 'ecdsa-with-SHA224',
76    '1.2.840.10045.4.3.2'           => 'ecdsa-with-SHA256',
77    '1.2.840.10045.4.3.3'           => 'ecdsa-with-SHA384',
78    '1.2.840.10045.4.3.4'           => 'ecdsa-with-SHA512',
79    '1.3.36.3.3.2.8.1.1.1'          => 'brainpoolP160r1',
80    '1.3.36.3.3.2.8.1.1.2'          => 'brainpoolP160t1',
81    '1.3.36.3.3.2.8.1.1.3'          => 'brainpoolP192r1',
82    '1.3.36.3.3.2.8.1.1.4'          => 'brainpoolP192t1',
83    '1.3.36.3.3.2.8.1.1.5'          => 'brainpoolP224r1',
84    '1.3.36.3.3.2.8.1.1.6'          => 'brainpoolP224t1',
85    '1.3.36.3.3.2.8.1.1.7'          => 'brainpoolP256r1',
86    '1.3.36.3.3.2.8.1.1.8'          => 'brainpoolP256t1',
87    '1.3.36.3.3.2.8.1.1.9'          => 'brainpoolP320r1',
88    '1.3.36.3.3.2.8.1.1.10'         => 'brainpoolP320t1',
89    '1.3.36.3.3.2.8.1.1.11'         => 'brainpoolP384r1',
90    '1.3.36.3.3.2.8.1.1.12'         => 'brainpoolP384t1',
91    '1.3.36.3.3.2.8.1.1.13'         => 'brainpoolP512r1',
92    '1.3.36.3.3.2.8.1.1.14'         => 'brainpoolP512t1',
93    '1.2.840.10045.3.1.1'           => 'secp192r1',
94    '1.3.132.0.1'                   => 'sect163k1',
95    '1.3.132.0.15'                  => 'sect163r2',
96    '1.3.132.0.33'                  => 'secp224r1',
97    '1.3.132.0.26'                  => 'sect233k1',
98    '1.3.132.0.27'                  => 'sect233r1',
99    '1.3.132.0.16'                  => 'sect283k1',
100    '1.3.132.0.17'                  => 'sect283r1',
101    '1.2.840.10045.3.1.7'           => 'secp256r1',
102    '1.3.132.0.34'                  => 'secp384r1',
103    '1.3.132.0.36'                  => 'sect409k1',
104    '1.3.132.0.37'                  => 'sect409r1',
105    '1.3.132.0.35'                  => 'secp521r1',
106    '1.3.132.0.38'                  => 'sect571k1',
107    '1.3.132.0.39'                  => 'sect571r1',
108#not std yet    '1.3.6.1.4.1.3029.1.5.1'        => 'curve25519', # GNU TLS
109#   '1.3.6.1.4.1.11591.7'           => 'curve25519', #ID josefsson-pkix-newcurves-00
110#   '1.3.6.1.4.1.11591.8'           => 'curve448', #ID josefsson-pkix-newcurves-00
111    '0.9.2342.19200300.100.1.25'    => 'domainComponent',
112    '0.9.2342.19200300.100.1.1'     => 'userID',
113    '2.5.4.7'                       => 'localityName',
114    '1.2.840.113549.1.1.11'         => [ 'sha256WithRSAEncryption', 'SHA-256 with RSA encryption' ],
115    '1.2.840.113549.1.1.12'         => 'sha384WithRSAEncryption',
116    '1.2.840.113549.1.1.13'         => [ 'sha512WithRSAEncryption', 'SHA-512 with RSA encryption' ],
117    '1.2.840.113549.1.1.14'         => 'sha224WithRSAEncryption',
118    '1.2.840.113549.1.1.2'          => [ 'md2WithRSAEncryption', 'MD2 with RSA encryption' ],
119    '1.2.840.113549.1.1.3'          => 'md4WithRSAEncryption',
120    '1.2.840.113549.1.1.6'          => 'rsaOAEPEncryptionSET',
121    '1.2.840.113549.1.1.7'          => 'RSAES-OAEP',
122    '1.2.840.113549.1.9.15'         => [ 'smimeCapabilities', 'SMIMECapabilities' ],
123    '1.3.14.3.2.29'                 => [ 'sha1WithRSAEncryption', 'SHA1 with RSA signature' ],
124    '1.3.6.1.4.1.311.13.1'          => 'RENEWAL_CERTIFICATE',          # Microsoft
125    '1.3.6.1.4.1.311.13.2.1'        => 'ENROLLMENT_NAME_VALUE_PAIR',   # Microsoft
126    '1.3.6.1.4.1.311.13.2.2'        => 'ENROLLMENT_CSP_PROVIDER',      # Microsoft
127    '1.3.6.1.4.1.311.2.1.14'        => 'CERT_EXTENSIONS',              # Microsoft
128    '1.3.6.1.5.2.3.5'               => [ 'keyPurposeKdc', 'KDC Authentication' ],
129    '1.3.6.1.5.5.7.9.5'             => 'countryOfResidence',
130    '2.16.840.1.101.3.4.2.1'        => [ 'sha256', 'SHA-256' ],
131    '2.16.840.1.101.3.4.2.2'        => [ 'sha384', 'SHA-384' ],
132    '2.16.840.1.101.3.4.2.3'        => [ 'sha512', 'SHA-512' ],
133    '2.16.840.1.101.3.4.2.4'        => [ 'sha224', 'SHA-224' ],
134    '2.16.840.1.101.3.4.3.1'        => 'dsaWithSha224',
135    '2.16.840.1.101.3.4.3.2'        => 'dsaWithSha256',
136    '2.16.840.1.101.3.4.3.3'        => 'dsaWithSha384',
137    '2.16.840.1.101.3.4.3.4'        => 'dsaWithSha512',
138    '2.5.4.12'                      => [ 'title', 'Title' ],
139    '2.5.4.13'                      => [ 'description', 'Description' ],
140    '2.5.4.14'                      => 'searchGuide',
141    '2.5.4.15'                      => 'businessCategory',
142    '2.5.4.16'                      => 'postalAddress',
143    '2.5.4.17'                      => 'postalCode',
144    '2.5.4.18'                      => 'postOfficeBox',
145    '2.5.4.19',                     => 'physicalDeliveryOfficeName',
146    '2.5.4.20',                     => 'telephoneNumber',
147    '2.5.4.23',                     => 'facsimileTelephoneNumber',
148    '2.5.4.4'                       => [ 'surname', 'Surname' ],
149    '2.5.4.41'                      => [ 'name', 'Name' ],
150    '2.5.4.42'                      => 'givenName',
151    '2.5.4.43'                      => 'initials',
152    '2.5.4.44'                      => 'generationQualifier',
153    '2.5.4.45'                      => 'uniqueIdentifier',
154    '2.5.4.46'                      => 'dnQualifier',
155    '2.5.4.51'                      => 'houseIdentifier',
156    '2.5.4.65'                      => 'pseudonym',
157    '2.5.4.5'                       => 'serialNumber',
158    '2.5.4.9'                       => 'streetAddress',
159    '2.5.29.32'                     => 'certificatePolicies',
160    '2.5.29.32.0'                   => 'anyPolicy',
161    '1.3.6.1.5.5.7.2.1'             => 'CPS',
162    '1.3.6.1.5.5.7.2.2'             => 'userNotice',
163);
164
165my %variantNames;
166
167foreach (keys %oids) {
168    my $val = $oids{$_};
169    if( ref $val ) {
170	$variantNames{$_} = $val;                   # OID to [ new, trad ]
171	$variantNames{$val->[0]} = $val->[1];       # New name to traditional for lookups
172	$variantNames{'$' . $val->[1]} = $val->[0]; # \$Traditional to new
173	$oids{$_} = $val->[!$apiVersion || 0];
174    }
175}
176
177my %oid2extkeyusage = (
178                '1.3.6.1.5.5.7.3.1'        => 'serverAuth',
179                '1.3.6.1.5.5.7.3.2'        => 'clientAuth',
180                '1.3.6.1.5.5.7.3.3'        => 'codeSigning',
181                '1.3.6.1.5.5.7.3.4'        => 'emailProtection',
182                '1.3.6.1.5.5.7.3.8'        => 'timeStamping',
183                '1.3.6.1.5.5.7.3.9'        => 'OCSPSigning',
184
185		'1.3.6.1.5.5.7.3.21'       => 'sshClient',
186		'1.3.6.1.5.5.7.3.22'       => 'sshServer',
187
188		# Microsoft usages
189
190                '1.3.6.1.4.1.311.10.3.1'   => 'msCTLSign',
191                '1.3.6.1.4.1.311.10.3.2'   => 'msTimeStamping',
192                '1.3.6.1.4.1.311.10.3.3'   => 'msSGC',
193                '1.3.6.1.4.1.311.10.3.4'   => 'msEFS',
194                '1.3.6.1.4.1.311.10.3.4.1' => 'msEFSRecovery',
195                '1.3.6.1.4.1.311.10.3.5'   => 'msWHQLCrypto',
196                '1.3.6.1.4.1.311.10.3.6'   => 'msNT5Crypto',
197                '1.3.6.1.4.1.311.10.3.7'   => 'msOEMWHQLCrypto',
198                '1.3.6.1.4.1.311.10.3.8'   => 'msEmbeddedNTCrypto',
199                '1.3.6.1.4.1.311.10.3.9'   => 'msRootListSigner',
200                '1.3.6.1.4.1.311.10.3.10'  => 'msQualifiedSubordination',
201                '1.3.6.1.4.1.311.10.3.11'  => 'msKeyRecovery',
202                '1.3.6.1.4.1.311.10.3.12'  => 'msDocumentSigning',
203                '1.3.6.1.4.1.311.10.3.13'  => 'msLifetimeSigning',
204                '1.3.6.1.4.1.311.10.3.14'  => 'msMobileDeviceSoftware',
205
206                '1.3.6.1.4.1.311.2.1.21'   => 'msCodeInd',
207                '1.3.6.1.4.1.311.2.1.22'   => 'msCodeCom',
208                '1.3.6.1.4.1.311.20.2.2'   => 'msSmartCardLogon',
209
210
211	        # Netscape
212                '2.16.840.1.113730.4.1'    => 'nsSGC',
213);
214
215my %shortnames = (
216		  countryName            => 'C',
217		  stateOrProvinceName    => 'ST',
218		  organizationName       => 'O',
219		  organizationalUnitName => 'OU',
220		  commonName             => 'CN',
221#		  emailAddress           => 'E', # Deprecated & not recognized by some software
222		  domainComponent        => 'DC',
223		  localityName           => 'L',
224		  userID                 => 'UID',
225		  surname                => 'SN',
226		  givenName              => 'GN',
227);
228
229my %name2oid;
230
231# For generating documentation, not part of API
232
233sub _cmpOID {
234    my @a = split( /\./, $a );
235    my @b = split( /\./, $b );
236
237    while( @a && @b ) {
238        my $c = shift @a <=> shift @b;
239        return $c if( $c );
240    }
241    return @a <=> @b;
242}
243
244sub __listOIDs {
245    my $class = shift;
246    my ( $hash ) = @_;
247
248    my @max = (0) x 3;
249    foreach my $oid ( keys %$hash ) {
250	my $len;
251
252	$len = length $oid;
253	$max[0] = $len if( $len > $max[0] );
254	if( exists $variantNames{$oid} ) {
255	    $len = length $variantNames{$oid}[0];
256	    $max[1] = $len if( $len > $max[1] );
257	    $len = length $variantNames{$oid}[1];
258	    $max[2] = $len if( $len > $max[2] );
259	} else {
260	    $len = length $hash->{$oid};
261	    $max[1] = $len if( $len > $max[1] );
262	}
263    }
264
265    printf( " %-*s %-*s %s\n %s %s %s\n", $max[0], 'OID',
266	                                  $max[1], 'Name (API v1)', 'Old Name (API v0)',
267	                                  '-' x $max[0], '-' x $max[1], '-' x $max[2] );
268
269    foreach my $oid ( sort _cmpOID keys %$hash ) {
270	printf( " %-*s %-*s", $max[0], $oid, $max[1], (exists $variantNames{$oid})?
271		                                         $variantNames{$oid}[0]: $hash->{$oid} );
272	printf( " (%-s)", $variantNames{$oid}[1] ) if( exists $variantNames{$oid} );
273	print( "\n" );
274    }
275    return;
276}
277
278sub _listOIDs {
279    my $class = shift;
280
281    $class->setAPIversion(1);
282    $class-> __listOIDs( { %oids, %oid2extkeyusage } );
283
284    return;
285}
286
287sub setAPIversion {
288    my( $class, $version ) = @_;
289
290    croak( substr(($error = "Wrong number of arguments\n"), 0, -1) ) unless( @_ == 2 && defined $class && !ref $class );
291    $version = 0 unless( defined $version );
292    croak( substr(($error = "Unsupported API version $version\n"), 0, -1) ) unless( $version >= 0 && $version <= 1 );
293    $apiVersion = $version;
294
295    $version = !$version || 0;
296
297    foreach (keys %variantNames) {
298	$oids{$_} = $variantNames{$_}[$version] if( /^\d/ ); # Map OID to selected name
299    }
300    %name2oid = reverse (%oids, %oid2extkeyusage);
301
302    return 1;
303}
304
305sub getAPIversion {
306    my( $class ) = @_;
307
308    croak( "Class not specified for getAPIversion()" ) unless( defined $class );
309
310    return $class->{_apiVersion} if( ref $class && $class->isa( __PACKAGE__ ) );
311
312    return $apiVersion;
313}
314
315sub name2oid {
316    my $class = shift;
317    my( $oid ) = @_;
318
319    croak( "Class not specifed for name2oid()" ) unless( defined $class );
320
321    return unless( defined $oid && defined $apiVersion && $apiVersion > 0 );
322
323    return $name2oid{$oid};
324}
325
326sub oid2name {
327    my $class = shift;
328    my( $oid ) = @_;
329
330    croak( "Class not specifed for oid2name()" ) unless( defined $class );
331
332    return $oid unless( defined $apiVersion && $apiVersion > 0 );
333
334    return $class->_oid2name( @_ );
335}
336
337# Should not be exported, as overloading may break ASN lookups
338
339sub _oid2name {
340    my $class = shift;
341    my( $oid ) = @_;
342
343    return unless($oid);
344
345    if( exists $oids{$oid} ) {
346	$oid = $oids{$oid};
347    }elsif( exists $oid2extkeyusage{$oid} ) {
348	$oid = $oid2extkeyusage{$oid};
349    }
350    return $oid;
351}
352
353# registerOID( $oid ) => true if $oid is registered, false if not
354# registerOID( $oid, $longname ) => Register an OID with its name
355# registerOID( $oid, $longname, $shortname ) => Register an OID with an abbreviation for RDNs.
356# registerOID( $oid, undef, $shortname ) => Register an abbreviation for RDNs for an existing OID
357
358sub registerOID {
359    my( $class, $oid, $longname, $shortname ) = @_;
360
361    croak( "Class not specifed for registerOID()" ) unless( defined $class );
362
363    unless( defined $apiVersion ) {
364	carp( "${class}::setAPIversion MUST be called before registerOID().  Defaulting to legacy mode" );
365	$class->setAPIversion(0);
366    }
367
368    return exists $oids{$oid} || exists $oid2extkeyusage{$oid} if( @_ == 2 && defined $oid );
369
370    croak( "Not enough arguments" )              unless( @_ >= 3 && defined $oid && ( defined $longname || defined $shortname ) );
371    croak( "Invalid OID $oid" )                  unless( defined $oid && $oid =~ /^\d+(?:\.\d+)*$/ );
372
373    if( defined $longname ) {
374        croak( "$oid already registered" )       if( exists $oids{$oid} || exists $oid2extkeyusage{$oid} );
375        croak( "$longname already registered" )  if( grep /^$longname$/, values %oids );
376    } else {
377        croak( "$oid not registered" )           unless( exists $oids{$oid} || exists $oid2extkeyusage{$oid} );
378    }
379    croak( "$shortname already registered" )     if( defined $shortname && grep /^\U$shortname\E$/,
380						                                          values %shortnames );
381
382    if( defined $longname ) {
383        $oids{$oid} = $longname;
384        $name2oid{$longname} = $oid;
385    } else {
386        $longname = $class->_oid2name( $oid );
387    }
388    $shortnames{$longname} = uc $shortname       if( defined $shortname );
389    return 1;
390}
391
392sub new {
393    my $class = shift;
394
395    undef $error;
396
397    $class = ref $class if( defined $class && ref $class && $class->isa( __PACKAGE__ ) );
398
399    unless( defined $apiVersion ) {
400	carp( "${class}::setAPIversion MUST be called before new().  Defaulting to legacy mode" );
401	$class->setAPIversion(0);
402    }
403
404    my( $void, $die ) = ( !defined wantarray, 0 );
405    my $self = eval {
406        die( "Insufficient arguments for new\n" ) unless( defined $class && @_ >= 1 );
407        die( "Value of Crypt::PKCS10->new ignored\n" ) if( $void );
408	return $class->_new( \$die, @_ );
409    }; if( $@ ) {
410	$error = $@;
411        if( !$apiVersion || $die || !defined wantarray ) {
412            1 while( chomp $@ );
413            croak( $@ );
414        }
415	return;
416    }
417
418    return $self;
419}
420
421sub error {
422    my $class = shift;
423
424    croak( "Class not specifed for error()" ) unless( defined $class );
425
426    if( ref $class && $class->isa( __PACKAGE__ ) ) {
427        return $class->{_error};
428    }
429    return $error;
430}
431
432my $pemre = qr/(?ms:^\r?-----BEGIN\s(?:NEW\s)?CERTIFICATE\sREQUEST-----\s*\r?\n\s*(.*?)\s*^\r?-----END\s(?:NEW\s)?CERTIFICATE\sREQUEST-----\r?$)/;
433
434sub _new {
435    my( $class, $die, $der ) = splice( @_, 0, 3 );
436
437    my %options = (
438                   acceptPEM       => 1,
439                   PEMonly         => 0,
440                   escapeStrings   => 1,
441                   readFile        => 0,
442                   ignoreNonBase64 => 0,
443                   verifySignature => ($apiVersion >= 1),
444                   dieOnError      => 0,
445                  );
446
447    %options = ( %options, %{ shift @_ } ) if( @_ >= 1 && ref( $_[0] ) eq 'HASH' );
448
449    die( "Every option to new() must have a value\n" ) unless( @_ % 2 == 0 );
450
451    %options = ( %options, @_ ) if( @_ );
452
453    my $self = { _apiVersion => $apiVersion };
454
455    my $keys = join( '|', qw/escapeStrings acceptPEM PEMonly binaryMode readFile verifySignature ignoreNonBase64 warnings dieOnError/ );
456
457    $self->{"_$_"} = delete $options{$_} foreach (grep { /^(?:$keys)$/ } keys %options);
458
459    $$die = $self->{_dieOnError} &&= $apiVersion >= 1;
460
461    die( "\$csr argument to new() is not defined\n" ) unless( defined $der );
462
463    if( keys %options ) {
464	die( "Invalid option(s) specified: " . join( ', ', sort keys %options ) . "\n" );
465    }
466
467    $self->{_binaryMode} = !$self->{_acceptPEM} unless( exists $self->{_binaryMode} );
468
469    my $parser;
470
471    # malformed requests can produce various warnings; don't proceed in that case.
472
473    local $SIG{__WARN__} = sub { my $msg = $_[0]; $msg =~ s/\A(.*?) at .*\Z/$1/s; 1 while( chomp $msg ); die "$msg\n" };
474
475    if( $self->{_readFile} ) {
476        open( my $fh, '<', $der ) or die( "Failed to open $der: $!\n" );
477        $der = $fh;
478    }
479
480    if( Scalar::Util::openhandle( $der ) ) {
481	local $/;
482
483	binmode $der if( $self->{_binaryMode} );
484
485	$der = <$der>;          # Note: this closes files opened by readFile
486	die( "Failed to read request: $!\n" ) unless( defined $der );
487    }
488
489    my $isPEM;
490
491    if( $self->{_PEMonly} ) {
492        if( $der =~ $pemre ) {
493            $der = $1;
494            $isPEM = 1;
495        } else {
496            die( "No certificate request found\n" );
497        }
498    } elsif( $self->{_acceptPEM} && $der =~ $pemre ) {
499        $der = $1;
500        $isPEM = 1;
501    }
502    if( $isPEM ) {
503	# Some versions of MIME::Base64 check the input.  Some don't.  Those that do
504	# seem to obey -w, but not 'use warnings'.  So we'll check here.
505
506	$der =~ s/\s+//g; # Delete whitespace, which is legal but meaningless
507        $der =~ tr~A-Za-z0-9+=/~~cd if( $self->{_ignoreNonBase64} );
508
509	unless( $der =~ m{\A[A-Za-z0-9+/]+={0,2}\z} && ( length( $der ) % 4 == 0 ) ) {
510	    warn( "Invalid base64 encoding\n" ); # Invalid character or length
511	}
512        $der = decode_base64( $der );
513    }
514
515    # some requests may contain information outside of the regular ASN.1 structure.
516    # This padding must be removed.
517
518    $der = eval { # Catch out of range errors caused by bad DER & report as format errors.
519        # SEQUENCE <len> -- CertificationRequest
520
521        my( $tlen, undef, $tag ) = asn_decode_tag2( $der );
522        die( "SEQUENCE not present\n" ) unless( $tlen && $tag == ASN_SEQUENCE );
523
524        my( $llen, $len ) = asn_decode_length( substr( $der, $tlen ) );
525        die( "Invalid SEQUENCE length\n" ) unless( $llen && $len );
526
527        $len += $tlen + $llen;
528        $tlen = length $der;
529        die( "DER too short to contain request\n" ) if( $tlen < $len );
530
531        if( $tlen != $len && $self->{_warnings} ) { # Debugging
532            local $SIG{__WARN__};
533            carp( sprintf( "DER length of %u contains %u bytes of padding",
534                           $tlen, $tlen - $len ) );
535        }
536        return substr( $der, 0, $len );
537    }; if( $@ ) {
538        1 while( chomp $@ );
539        die( "Invalid format for request: $@\n" );
540    }
541
542    $self->{_der} = $der;
543
544    bless( $self, $class );
545
546    $self->{_bmpenc} = Encode::find_encoding('UCS2-BE');
547
548    my $asn = Convert::ASN1->new;
549    $self->{_asn} = $asn;
550    $asn->prepare(<<ASN1) or die( "Internal error in " . __PACKAGE__ . ": " . $asn->error );
551
552    DirectoryString ::= CHOICE {
553      teletexString   TeletexString,
554      printableString PrintableString,
555      bmpString       BMPString,
556      universalString UniversalString,
557      utf8String      UTF8String,
558      ia5String       IA5String,
559      integer         INTEGER}
560
561    Algorithms ::= ANY
562
563    Name ::= SEQUENCE OF RelativeDistinguishedName
564    RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
565    AttributeTypeAndValue ::= SEQUENCE {
566      type  OBJECT IDENTIFIER,
567      value DirectoryString}
568
569    Attributes ::= SET OF Attribute
570    Attribute ::= SEQUENCE {
571      type   OBJECT IDENTIFIER,
572      values SET OF ANY}
573
574
575    AlgorithmIdentifier ::= SEQUENCE {
576      algorithm  OBJECT IDENTIFIER,
577      parameters Algorithms OPTIONAL}
578
579    SubjectPublicKeyInfo ::= SEQUENCE {
580      algorithm        AlgorithmIdentifier,
581      subjectPublicKey BIT STRING}
582
583    --- Certificate Request ---
584
585    CertificationRequest ::= SEQUENCE {
586      certificationRequestInfo  CertificationRequestInfo,
587      signatureAlgorithm        AlgorithmIdentifier,
588      signature                 BIT STRING},
589
590    CertificationRequestInfo ::= SEQUENCE {
591      version       INTEGER ,
592      subject       Name OPTIONAL,
593      subjectPKInfo SubjectPublicKeyInfo,
594      attributes    [0] Attributes OPTIONAL}
595
596    --- Extensions ---
597
598    BasicConstraints ::= SEQUENCE {
599        cA                  BOOLEAN OPTIONAL, -- DEFAULT FALSE,
600        pathLenConstraint   INTEGER OPTIONAL}
601
602    OS_Version ::= IA5String
603    emailAddress ::= IA5String
604
605    EnrollmentCSP ::= SEQUENCE {
606        KeySpec     INTEGER,
607        Name        BMPString,
608        Signature   BIT STRING}
609
610    ENROLLMENT_CSP_PROVIDER ::= SEQUENCE { -- MSDN
611        keySpec     INTEGER,
612        cspName     BMPString,
613        signature   BIT STRING}
614
615    ENROLLMENT_NAME_VALUE_PAIR ::= EnrollmentNameValuePair -- MSDN: SEQUENCE OF
616
617    EnrollmentNameValuePair ::= SEQUENCE { -- MSDN
618         name       BMPString,
619         value      BMPString}
620
621    ClientInformation ::= SEQUENCE { -- MSDN
622        clientId       INTEGER,
623        MachineName    UTF8String,
624        UserName       UTF8String,
625        ProcessName    UTF8String}
626
627    extensionRequest ::= SEQUENCE OF Extension
628    Extension ::= SEQUENCE {
629      extnID    OBJECT IDENTIFIER,
630      critical  BOOLEAN OPTIONAL,
631      extnValue OCTET STRING}
632
633    SubjectKeyIdentifier ::= OCTET STRING
634
635    certificateTemplate ::= SEQUENCE {
636       templateID              OBJECT IDENTIFIER,
637       templateMajorVersion    INTEGER OPTIONAL, -- (0..4294967295)
638       templateMinorVersion    INTEGER OPTIONAL} -- (0..4294967295)
639
640    EnhancedKeyUsage ::= SEQUENCE OF OBJECT IDENTIFIER
641    KeyUsage ::= BIT STRING
642    netscapeCertType ::= BIT STRING
643
644    ApplicationCertPolicies ::= SEQUENCE OF PolicyInformation -- Microsoft
645
646    PolicyInformation ::= SEQUENCE {
647        policyIdentifier   OBJECT IDENTIFIER,
648        policyQualifiers   SEQUENCE OF PolicyQualifierInfo OPTIONAL}
649
650    PolicyQualifierInfo ::= SEQUENCE {
651       policyQualifierId    OBJECT IDENTIFIER,
652       qualifier            ANY}
653
654    certificatePolicies ::= SEQUENCE OF certPolicyInformation -- RFC 3280
655
656    certPolicyInformation ::= SEQUENCE {
657        policyIdentifier    CertPolicyId,
658        policyQualifier     SEQUENCE OF certPolicyQualifierInfo OPTIONAL}
659
660    CertPolicyId ::= OBJECT IDENTIFIER
661
662    certPolicyQualifierInfo ::= SEQUENCE {
663        policyQualifierId CertPolicyQualifierId,
664        qualifier         ANY DEFINED BY policyQualifierId}
665
666    CertPolicyQualifierId ::= OBJECT IDENTIFIER
667
668    CertPolicyQualifier ::= CHOICE {
669        cPSuri     CPSuri,
670        userNotice UserNotice }
671
672    CPSuri ::= IA5String
673
674    UserNotice ::= SEQUENCE {
675        noticeRef     NoticeReference OPTIONAL,
676        explicitText  DisplayText OPTIONAL}
677
678    NoticeReference ::= SEQUENCE {
679        organization     DisplayText,
680        noticeNumbers    SEQUENCE OF INTEGER }
681
682    DisplayText ::= CHOICE {
683        ia5String        IA5String,
684        visibleString    VisibleString,
685        bmpString        BMPString,
686        utf8String       UTF8String }
687
688    unstructuredName ::= CHOICE {
689        Ia5String       IA5String,
690        directoryString DirectoryString}
691
692    challengePassword ::= DirectoryString
693
694    subjectAltName ::= SEQUENCE OF GeneralName
695
696    GeneralName ::= CHOICE {
697         otherName                       [0]     AnotherName,
698         rfc822Name                      [1]     IA5String,
699         dNSName                         [2]     IA5String,
700         x400Address                     [3]     ANY, --ORAddress,
701         directoryName                   [4]     Name,
702         ediPartyName                    [5]     EDIPartyName,
703         uniformResourceIdentifier       [6]     IA5String,
704         iPAddress                       [7]     OCTET STRING,
705         registeredID                    [8]     OBJECT IDENTIFIER}
706
707    AnotherName ::= SEQUENCE {
708         type           OBJECT IDENTIFIER,
709         value      [0] EXPLICIT ANY }
710
711    EDIPartyName ::= SEQUENCE {
712         nameAssigner            [0]     DirectoryString OPTIONAL,
713         partyName               [1]     DirectoryString }
714
715    certificateTemplateName ::= CHOICE {
716        octets          OCTET STRING,
717        directoryString DirectoryString}
718
719    rsaKey ::= SEQUENCE {
720        modulus         INTEGER,
721        publicExponent  INTEGER}
722
723    dsaKey  ::= INTEGER
724
725    dsaPars ::= SEQUENCE {
726        P               INTEGER,
727        Q               INTEGER,
728        G               INTEGER}
729
730    eccName ::= OBJECT IDENTIFIER
731
732    ecdsaSigValue ::= SEQUENCE {
733        r               INTEGER,
734        s               INTEGER}
735ASN1
736
737    $asn->registertype( 'qualifier', '1.3.6.1.5.5.7.2.1', $self->_init('CPSuri') );
738    $asn->registertype( 'qualifier', '1.3.6.1.5.5.7.2.2', $self->_init('UserNotice') );
739
740    $parser = $self->_init( 'CertificationRequest' );
741
742    my $top =
743	$parser->decode( $der ) or
744	  confess( "decode: " . $parser->error .
745		   "Cannot handle input or missing ASN.1 definitions" );
746
747    $self->{certificationRequestInfo}{subject_raw}
748        = $top->{certificationRequestInfo}{subject};
749
750    $self->{certificationRequestInfo}{subject}
751        = $self->_convert_rdn( $top->{certificationRequestInfo}{subject} );
752
753    $self->{certificationRequestInfo}{version}
754        = $top->{certificationRequestInfo}{version};
755
756    $self->{certificationRequestInfo}{attributes} = $self->_convert_attributes(
757        $top->{certificationRequestInfo}{attributes} );
758
759    $self->{_pubkey} = "-----BEGIN PUBLIC KEY-----\n" .
760      _encode_PEM( $self->_init('SubjectPublicKeyInfo')->
761                   encode( $top->{certificationRequestInfo}{subjectPKInfo} ) ) .
762                     "-----END PUBLIC KEY-----\n";
763
764    $self->{certificationRequestInfo}{subjectPKInfo} = $self->_convert_pkinfo(
765        $top->{certificationRequestInfo}{subjectPKInfo} );
766
767    $self->{signature} = $top->{signature};
768
769    $self->{signatureAlgorithm}
770        = $self->_convert_signatureAlgorithm( $top->{signatureAlgorithm} );
771
772    # Extract bundle of bits that is signed
773    # The DER is SEQUENCE -- CertificationRequest
774    #              SEQUENCE -- CertificationRequestInfo [SIGNED]
775
776    my( $CRtaglen, $CRtag, $CRllen, $CRlen );
777    ($CRtaglen, undef, $CRtag) = asn_decode_tag2( $der );
778    die( "Invalid CSR format: missing SEQUENCE 1\n" ) unless( $CRtag == ASN_SEQUENCE );
779    ($CRllen, $CRlen) = asn_decode_length( substr( $der, $CRtaglen ) );
780
781    my( $CItaglen, $CItag, $CIllen, $CIlen );
782    ($CItaglen, undef, $CItag) = asn_decode_tag2( substr( $der, $CRtaglen + $CRllen ) );
783    die( "Invalid CSR format: missing SEQUENCE 2\n" ) unless( $CItag == ASN_SEQUENCE );
784    ($CIllen, $CIlen) = asn_decode_length( substr( $der, $CRtaglen + $CRllen + $CItaglen ) );
785
786    $self->{_signed} = substr( $der, $CRtaglen +  $CRllen, $CItaglen + $CIllen + $CIlen );
787
788    die( $error ) if( $self->{_verifySignature} && !$self->checkSignature );
789
790    return $self;
791}
792
793# Convert::ASN1 returns BMPStrings as 16-bit fixed-width characters, e.g. UCS2-BE
794
795sub _bmpstring {
796    my $self = shift;
797
798    my $enc = $self->{_bmpenc};
799
800    $_ = $enc->decode( $_ ) foreach (@_);
801
802    return;
803}
804
805# Find the obvious BMPStrings in a value and convert them
806# This doesn't catch direct values, but does find them in hashes
807# (generally as a result of a CHOICE)
808#
809# Convert iPAddresses as well
810
811sub _scanvalue {
812    my $self = shift;
813
814    my( $value ) = @_;
815
816    return unless( ref $value );
817    if( ref $value eq 'ARRAY' ) {
818	foreach (@$value) {
819	    $self->_scanvalue( $_ );
820	}
821	return;
822    }
823    if( ref $value eq 'HASH' ) {
824	foreach my $k (keys %$value) {
825	    if( $k eq 'bmpString' ) {
826		$self->_bmpstring( $value->{bmpString} );
827		next;
828	    }
829	    if( $k eq 'iPAddress' ) {
830		use bytes;
831		my $addr = $value->{iPAddress};
832		if( length $addr == 4 ) {
833		    $value->{iPAddress} = sprintf( '%vd', $addr );
834		} else {
835		    $addr = sprintf( '%*v02X', ':', $addr );
836		    $addr =~ s/([[:xdigit:]]{2}):([[:xdigit:]]{2})/$1$2/g;
837		    $value->{iPAddress} = $addr;
838		}
839		next;
840	    }
841	    $self->_scanvalue( $value->{$k} );
842	}
843	return;
844    }
845    return;
846}
847
848sub _convert_signatureAlgorithm {
849    my $self = shift;
850
851    my $signatureAlgorithm = shift;
852    $signatureAlgorithm->{algorithm}
853        = $oids{$signatureAlgorithm->{algorithm}}
854	  if( defined $signatureAlgorithm->{algorithm}
855	    && exists $oids{$signatureAlgorithm->{algorithm}} );
856
857    return $signatureAlgorithm;
858}
859
860sub _convert_pkinfo {
861    my $self = shift;
862
863    my $pkinfo = shift;
864
865    $pkinfo->{algorithm}{algorithm}
866        = $oids{$pkinfo->{algorithm}{algorithm}}
867	  if( defined $pkinfo->{algorithm}{algorithm}
868	    && exists $oids{$pkinfo->{algorithm}{algorithm}} );
869    return $pkinfo;
870}
871
872# OIDs requiring some sort of special handling
873#
874# Called with decoded value, returns updated value.
875# Key is ASN macro name
876
877my %special;
878%special =
879(
880 EnhancedKeyUsage => sub {
881     my $self = shift;
882     my( $value, $id ) = @_;
883
884     foreach (@{$value}) {
885	 $_ = $oid2extkeyusage{$_} if(defined $oid2extkeyusage{$_});
886     }
887     return $value;
888 },
889 KeyUsage => sub {
890     my $self = shift;
891     my( $value, $id ) = @_;
892
893     my $bit =  unpack('C*', @{$value}[0]); #get the decimal representation
894     my $length = int(log($bit) / log(2) + 1); #get its bit length
895     my @usages = reverse( $id eq 'KeyUsage'? # Following are in order from bit 0 upwards
896			   qw(digitalSignature nonRepudiation keyEncipherment dataEncipherment
897                              keyAgreement keyCertSign cRLSign encipherOnly decipherOnly) :
898			   qw(client server email objsign reserved sslCA emailCA objCA) );
899     my $shift = ($#usages + 1) - $length; # computes the unused area in @usages
900
901     @usages = @usages[ grep { $bit & (1 << $_ - $shift) } 0 .. $#usages ]; #transfer bitmap to barewords
902
903     return [ @usages ] if( $self->{_apiVersion} >= 1 );
904
905     return join( ', ', @usages );
906 },
907 netscapeCertType => sub {
908     goto &{$special{KeyUsage}};
909 },
910 SubjectKeyIdentifier => sub {
911     my $self = shift;
912     my( $value, $id ) = @_;
913
914     return unpack( "H*", $value );
915 },
916 ApplicationCertPolicies => sub {
917     goto &{$special{certificatePolicies}} if( $_[0]->{_apiVersion} > 0 );
918
919     my $self = shift;
920     my( $value, $id ) = @_;
921
922     foreach my $entry (@{$value}) {
923	 $entry->{policyIdentifier} = $self->_oid2name( $entry->{policyIdentifier} );
924     }
925
926     return $value;
927 },
928 certificateTemplate => sub {
929     my $self = shift;
930     my( $value, $id ) = @_;
931
932     $value->{templateID} = $self->_oid2name( $value->{templateID} ) if( $self->{_apiVersion} > 0 );
933     return $value;
934 },
935 ENROLLMENT_NAME_VALUE_PAIR => sub {
936     my $self = shift;
937     my( $value, $id ) = @_;
938
939     $self->_bmpstring( @{$value}{qw/name value/} );
940
941     return $value;
942 },
943 EnrollmentCSP => sub {
944     my $self = shift;
945     my( $value, $id ) = @_;
946
947     $self->_bmpstring( $value->{Name} );
948
949     return $value;
950 },
951 ENROLLMENT_CSP_PROVIDER => sub {
952     my $self = shift;
953     my( $value, $id ) = @_;
954
955     $self->_bmpstring( $value->{cspName} );
956
957     return $value;
958 },
959 certificatePolicies => sub {
960     my $self = shift;
961     my( $value, $id ) = @_;
962
963     foreach my $policy (@$value) {
964	 $policy->{policyIdentifier} = $self->_oid2name( $policy->{policyIdentifier} );
965	 if( exists $policy->{policyQualifier} ) {
966	     foreach my $qualifier (@{$policy->{policyQualifier}}) {
967		 $qualifier->{policyQualifierId} = $self->_oid2name( $qualifier->{policyQualifierId} );
968		 my $qv = $qualifier->{qualifier};
969		 if( ref $qv eq 'HASH' ) {
970		     foreach my $qt (keys %$qv) {
971			 if( $qt eq 'explicitText' ) {
972			     $qv->{$qt} = (values %{$qv->{$qt}})[0];
973			 } elsif( $qt eq 'noticeRef' ) {
974			     my $userNotice = $qv->{$qt};
975			     $userNotice->{organization} = (values %{$userNotice->{organization}})[0];
976			 }
977		     }
978		     $qv->{userNotice} = delete $qv->{noticeRef}
979		       if( exists $qv->{noticeRef} );
980		 }
981	     }
982	 }
983     }
984     return $value;
985 },
986 CERT_EXTENSIONS => sub {
987     my $self = shift;
988     my( $value, $id, $entry ) = @_;
989
990     return $self->_convert_extensionRequest( [ $value ] ) if( $self->{_apiVersion} > 0 ); # Untested
991 },
992 BasicConstraints => sub {
993     my $self = shift;
994     my( $value, $id, $entry ) = @_;
995
996     my $r = {
997	      CA => $value->{cA}? 'TRUE' : 'FALSE',
998	     };
999     my $string = "CA:$r->{CA}";
1000
1001     if( exists $value->{pathLenConstraint} ) {
1002	 $r->{pathlen} = $value->{pathLenConstraint};
1003	 $string .= sprintf( ',pathlen:%u', $value->{pathLenConstraint} );
1004     }
1005     $entry->{_FMT} = [ $r, $string ]; # [ Raw, formatted ]
1006     return $value;
1007 },
1008 unstructuredName => sub {
1009     my $self = shift;
1010     my( $value, $id ) = @_;
1011
1012     return $self->_hash2string( $value );
1013 },
1014 challengePassword => sub {
1015     my $self = shift;
1016     my( $value, $id ) = @_;
1017
1018     return $self->_hash2string( $value );
1019 },
1020); # %special
1021
1022sub _convert_attributes {
1023    my $self = shift;
1024    my( $typeandvalues ) = @_;
1025
1026    foreach my $entry ( @{$typeandvalues} ) {
1027	my $oid = $entry->{type};
1028	my $name = $oids{$oid};
1029	$name = $variantNames{$name} if( defined $name && exists $variantNames{$name} );
1030
1031	next unless( defined $name );
1032
1033	$entry->{type} = $name;
1034
1035	if ($name eq 'extensionRequest') {
1036	    $entry->{values} = $self->_convert_extensionRequest($entry->{values}[0]);
1037	} else {
1038	    my $parser = $self->_init( $name, 1 ) or next; # Skip unknown attributes
1039
1040	    if($entry->{values}[1]) {
1041		confess( "Incomplete parsing of attribute type: $name" );
1042	    }
1043	    my $value = $entry->{values} = $parser->decode( $entry->{values}[0] ) or
1044	      confess( "Looks like damaged input parsing attribute $name" );
1045
1046	    if( exists $special{$name} ) {
1047		my $action = $special{$name};
1048		$entry->{values} = $action->( $self, $value, $name, $entry );
1049	    }
1050	}
1051    }
1052    return $typeandvalues;
1053}
1054
1055sub _convert_extensionRequest {
1056    my $self = shift;
1057    my( $extensionRequest ) = @_;
1058
1059    my $parser = $self->_init('extensionRequest');
1060    my $decoded = $parser->decode($extensionRequest) or return [];
1061
1062    foreach my $entry (@{$decoded}) {
1063	my $name = $oids{ $entry->{extnID} };
1064	$name = $variantNames{$name} if( defined $name && exists $variantNames{$name} );
1065        if (defined $name) {
1066	    my $asnName = $name;
1067	    $asnName =~ tr/ //d;
1068            my $parser = $self->_init($asnName, 1);
1069            if(!$parser) {
1070                $entry = undef;
1071                next;
1072            }
1073            $entry->{extnID} = $name;
1074            my $dec = $parser->decode($entry->{extnValue}) or
1075	      confess( $parser->error . ".. looks like damaged input parsing extension $asnName" );
1076
1077	    $self->_scanvalue( $dec );
1078
1079	    if( exists $special{$asnName} ) {
1080		my $action = $special{$asnName};
1081		$dec = $action->( $self, $dec, $asnName, $entry );
1082	    }
1083	    $entry->{extnValue} = $dec;
1084        }
1085    }
1086    @{$decoded} = grep { defined } @{$decoded};
1087    return $decoded;
1088}
1089
1090sub _convert_rdn {
1091    my $self = shift;
1092    my $typeandvalue = shift;
1093    my %hash = ( _subject => [], );
1094    foreach my $entry ( @$typeandvalue ) {
1095	foreach my $item (@$entry) {
1096	    my $oid = $item->{type};
1097	    my $name = (exists $variantNames{$oid})? $variantNames{$oid}[1]: $oids{ $oid };
1098	    if( defined $name ) {
1099		push @{$hash{$name}}, sort values %{$item->{value}};
1100		push @{$hash{_subject}}, $name, [ sort values %{$item->{value}} ];
1101		my @names = (exists $variantNames{$oid})? @{$variantNames{$oid}} : ( $name );
1102		foreach my $name ( @names ) {
1103		    unless( $self->can( $name ) ) {
1104			no strict 'refs'; ## no critic
1105			*$name =  sub {
1106			    my $self = shift;
1107			    return @{ $self->{certificationRequestInfo}{subject}{$name} } if( wantarray );
1108			    return $self->{certificationRequestInfo}{subject}{$name}[0] || '';
1109			}
1110		    }
1111		}
1112	    }
1113	}
1114    }
1115
1116    return \%hash;
1117}
1118
1119sub _init {
1120    my $self = shift;
1121    my( $node, $optional ) = @_;
1122
1123    my $parsed = $self->{_asn}->find($node);
1124
1125    unless( defined $parsed || $optional ) {
1126	croak( "Missing node $node in ASN.1" );
1127    }
1128    return $parsed;
1129}
1130
1131###########################################################################
1132# interface methods
1133
1134sub csrRequest {
1135    my $self = shift;
1136    my $format = shift;
1137
1138    return( "-----BEGIN CERTIFICATE REQUEST-----\n" .
1139	    _encode_PEM( $self->{_der} ) .
1140	    "-----END CERTIFICATE REQUEST-----\n" ) if( $format );
1141
1142    return $self->{_der};
1143}
1144
1145# Common subject components documented to be always present:
1146
1147foreach my $component (qw/commonName organizationalUnitName organizationName
1148                          emailAddress stateOrProvinceName countryName domainComponent/ ) {
1149    no strict 'refs'; ## no critic
1150
1151    unless( defined &$component ) {
1152	*$component = sub {
1153	    my $self = shift;
1154	    return @{ $self->{certificationRequestInfo}{subject}{$component} || [] } if( wantarray );
1155	    return $self->{certificationRequestInfo}{subject}{$component}[0] || '';
1156	}
1157    }
1158}
1159
1160# Complete subject
1161
1162sub subject {
1163    my $self = shift;
1164    my $long = shift;
1165
1166    return @{ $self->{certificationRequestInfo}{subject}{_subject} } if( wantarray );
1167
1168    my @subject = @{ $self->{certificationRequestInfo}{subject}{_subject} };
1169
1170    my $subj = '';
1171    while( @subject ) {
1172	my( $name, $value ) = splice( @subject, 0, 2 );
1173	$name = $shortnames{$name} if( !$long && exists $shortnames{$name} );
1174	$subj .= "/$name=" . join( ',', @$value );
1175    }
1176
1177    return $subj;
1178}
1179
1180
1181sub subjectRaw {
1182
1183    my $self = shift;
1184    my @subject;
1185    foreach my $rdn (@{$self->{certificationRequestInfo}{subject_raw}}) {
1186        my @sequence = map {
1187            $_->{format} = (keys %{$_->{value}})[0];
1188            $_->{value} = (values %{$_->{value}})[0];
1189            $_;
1190        } @{$rdn};
1191        if (scalar @sequence > 1) {
1192            push @subject, \@sequence;
1193        } else {
1194            push @subject, $sequence[0];
1195        }
1196    }
1197    return \@subject;
1198
1199}
1200
1201
1202sub subjectAltName {
1203    my $self = shift;
1204    my( $type ) = @_;
1205
1206    my $san = $self->extensionValue( 'subjectAltName' );
1207    unless( defined $san ) {
1208	return () if( wantarray );
1209	return undef;  ## no critic
1210    }
1211
1212    if( !defined $type ) {
1213	if( wantarray ) {
1214	    my %comps;
1215	    $comps{$_} = 1 foreach (map { keys %$_ } @$san);
1216	    return sort keys %comps; ## no critic
1217	}
1218	my @string;
1219	foreach my $comp (@$san) {
1220	    push @string, join( '+', map { "$_:$comp->{$_}" } sort keys %$comp );
1221	}
1222	return join( ',', @string );
1223    }
1224
1225    my $result = [ map { $_->{$type} } grep { exists $_->{$type} } @$san ];
1226
1227    return @$result if( wantarray );
1228    return $result->[0];
1229}
1230
1231sub version {
1232    my $self = shift;
1233    my $v = $self->{certificationRequestInfo}{version};
1234    return sprintf( "v%u", $v+1 );
1235}
1236
1237sub pkAlgorithm {
1238    my $self = shift;
1239    return $self->{certificationRequestInfo}{subjectPKInfo}{algorithm}{algorithm};
1240}
1241
1242sub subjectPublicKey {
1243    my $self = shift;
1244    my $format = shift;
1245
1246    return $self->{_pubkey} if( $format );
1247    return unpack('H*', $self->{certificationRequestInfo}{subjectPKInfo}{subjectPublicKey}[0]);
1248}
1249
1250sub subjectPublicKeyParams {
1251    my $self = shift;
1252    my $detail = shift;
1253
1254    croak( "Requires API version 1" ) unless( $self->{_apiVersion} >= 1 );
1255
1256    undef $error;
1257    delete $self->{_error};
1258
1259    my $rv = {};
1260    my $at = $self->pkAlgorithm;
1261    $at = 'undef' unless( defined $at );
1262
1263    if( $at eq 'rsaEncryption' ) {
1264        $rv->{keytype} = 'RSA';
1265        my $par = $self->_init( 'rsaKey' );
1266        my $rsa = $par->decode( $self->{certificationRequestInfo}{subjectPKInfo}{subjectPublicKey}[0] );
1267        $rv->{keylen} = 4 * ( length( $rsa->{modulus}->as_hex ) -2 ); # 2 == length( '0x' )
1268        $rv->{modulus} = substr( $rsa->{modulus}->as_hex, 2 );
1269        $rv->{publicExponent} = ( ref( $rsa->{publicExponent} )?
1270                                  $rsa->{publicExponent}->as_hex :
1271                                  sprintf( '%x', $rsa->{publicExponent} ) );
1272    } elsif( $at eq 'ecPublicKey' ) {
1273        $rv->{keytype} = 'ECC';
1274
1275        eval { require Crypt::PK::ECC; };
1276        if( $@ ) {
1277            $rv->{keytype} = undef;
1278            $self->{_error} =
1279              $error = "ECC public key requires Crypt::PK::ECC\n";
1280            croak( $error ) if( $self->{_dieOnError} );
1281            return $rv;
1282        }
1283        my $key = $self->subjectPublicKey(1);
1284        $key = Crypt::PK::ECC->new( \$key )->key2hash;
1285        $rv->{keylen} = $key->{curve_bits};
1286        $rv->{pub_x}  = $key->{pub_x};
1287        $rv->{pub_y}  = $key->{pub_y};
1288        $rv->{detail} = { %$key } if( $detail );
1289
1290        my $par = $self->_init( 'eccName' );
1291        $rv->{curve} = $par->decode( $self->{certificationRequestInfo}{subjectPKInfo}{algorithm}{parameters} );
1292        $rv->{curve} = $self->_oid2name( $rv->{curve} ) if ($rv->{curve});
1293    } elsif( $at eq 'dsa' ) {
1294        $rv->{keytype} = 'DSA';
1295        my $par = $self->_init( 'dsaKey' );
1296        my $dsa = $par->decode( $self->{certificationRequestInfo}{subjectPKInfo}{subjectPublicKey}[0] );
1297        $rv->{keylen} = 4 * ( length( $dsa->as_hex ) -2 );
1298        if( exists $self->{certificationRequestInfo}{subjectPKInfo}{algorithm}{parameters} ) {
1299            $par = $self->_init('dsaPars');
1300            $dsa = $par->decode($self->{certificationRequestInfo}{subjectPKInfo}{algorithm}{parameters});
1301            $rv->{G} = substr( $dsa->{G}->as_hex, 2 );
1302            $rv->{P} = substr( $dsa->{P}->as_hex, 2 );
1303            $rv->{Q} = substr( $dsa->{Q}->as_hex, 2 );
1304        }
1305    } else {
1306        $rv->{keytype} = undef;
1307        $self->{_error} =
1308          $error = "Unrecognized public key type $at\n";
1309        croak( $error ) if( $self->{_dieOnError} );
1310    }
1311    return $rv;
1312}
1313
1314sub signatureAlgorithm {
1315    my $self = shift;
1316    return $self->{signatureAlgorithm}{algorithm};
1317}
1318
1319sub signatureParams {
1320    my $self = shift;
1321
1322    if( exists $self->{signatureAlgorithm}{parameters} ) {
1323        my( $tlen, undef, $tag ) = asn_decode_tag2( $self->{signatureAlgorithm}{parameters} );
1324        if( $tlen != 0 && $tag != ASN_NULL ) {
1325            return $self->{signatureAlgorithm}{parameters}
1326        }
1327    }
1328    # Known algorithm's parameters MAY return a hash of decoded fields.
1329    # For now, leaving that to the caller...
1330
1331    return;
1332}
1333
1334sub signature {
1335    my $self = shift;
1336    my $format = shift;
1337
1338    if( defined $format && $format == 2 ) { # Per keytype decoding
1339        if( $self->pkAlgorithm eq 'ecPublicKey' ) { # ECDSA
1340            my $par = $self->_init( 'ecdsaSigValue' );
1341            return $par->decode( $self->{signature}[0] );
1342        }
1343        return;                             # Unknown
1344    }
1345    return $self->{signature}[0] if( $format );
1346
1347    return unpack('H*', $self->{signature}[0]);
1348}
1349
1350sub certificationRequest {
1351    my $self = shift;
1352
1353    return $self->{_signed};
1354}
1355
1356sub _attributes {
1357    my $self = shift;
1358
1359    my $attributes = $self->{certificationRequestInfo}{attributes};
1360    return unless( defined $attributes );
1361
1362    return { map { $_->{type} => $_->{values} } @$attributes };
1363}
1364
1365sub attributes {
1366    my $self = shift;
1367    my( $name ) = @_;
1368
1369    if( $self->{_apiVersion} < 1 ) {
1370	my $attributes = $self->{certificationRequestInfo}{attributes};
1371	return () unless( defined $attributes );
1372
1373	my %hash = map { $_->{type} => $_->{values} }
1374	  @{$attributes};
1375	return %hash;
1376    }
1377
1378    my $attributes = $self->_attributes;
1379    unless( defined $attributes ) {
1380	return () if( wantarray );
1381	return undef;  ## no critic
1382    }
1383
1384    unless( defined $name ) {
1385	return grep { $_  ne 'extensionRequest' } sort keys %$attributes;
1386    }
1387
1388    $name = $self->_oid2name( $name );
1389
1390    if( $name eq 'extensionRequest' ) { # Meaningless, and extensions/extensionValue handle
1391	return () if( wantarray );
1392	return undef; ## no critic
1393    }
1394
1395    # There can only be one matching the name.
1396    # If the match becomes wider, sort the keys.
1397
1398
1399    my @attrs = grep { $_ eq $name } keys %$attributes;
1400    unless( @attrs ) {
1401	return () if( wantarray );
1402	return undef; ## no critic
1403    }
1404
1405    my @values;
1406    foreach my $attr (@attrs) {
1407	my $values = $attributes->{$attr};
1408	$values = [ $values ] unless( ref $values eq 'ARRAY' );
1409	foreach my $value (@$values)  {
1410	    my $value = $self->_hash2string( $value );
1411	    push @values, (wantarray? $value : $self->_value2strings( $value ));
1412	}
1413    }
1414    return @values if( wantarray );
1415
1416    if( @values == 1 ) {
1417	$values[0] =~ s/^\((.*)\)$/$1/;
1418	return $values[0];
1419    }
1420    return join( ',', @values );
1421}
1422
1423sub certificateTemplate {
1424    my $self = shift;
1425
1426    return $self->extensionValue( 'certificateTemplate', @_ );
1427}
1428
1429# If a hash contains one string (e.g. a CHOICE containing type=>value), return the string.
1430# If the hash is nested, try recursing.
1431# If the string can't be identified (clutter in the hash), return the hash
1432# Some clutter can be filtered by specifying $exclude (a regexp)
1433
1434sub _hash2string {
1435    my $self = shift;
1436    my( $hash, $exclude ) = @_;
1437
1438    return $hash unless( ref $hash eq 'HASH' );
1439
1440    my @keys = keys %$hash;
1441
1442    @keys = grep { $_ !~ /$exclude/ } @keys if( defined $exclude );
1443
1444    return $hash if( @keys != 1 );
1445
1446    return $self->_hash2string( $hash->{$keys[0]} ) if( ref $hash->{$keys[0]} eq 'HASH' );
1447
1448    return $hash->{$keys[0]};
1449}
1450
1451# Convert a value to a printable string
1452
1453sub _value2strings {
1454    my $self = shift;
1455    my( $value ) = @_;
1456
1457    my @strings;
1458    if( ref $value eq 'ARRAY' ) {
1459	foreach my $value (@$value) {
1460	    push @strings, $self->_value2strings( $value );
1461	}
1462	return '(' . join( ',', @strings ) . ')' if( @strings > 1 );
1463	return join( ',', @strings );
1464    }
1465    if( ref $value eq 'HASH' ) {
1466	foreach my $k (sort keys %$value) {
1467	    push @strings, "$k=" . $self->_value2strings( $value->{$k} );
1468	}
1469	return '(' . join( ',', @strings ) . ')' if( @strings > 1 );
1470	return join( ',', @strings );
1471    }
1472
1473    return $value if( $value =~ /^\d+$/ );
1474
1475    # OpenSSL and Perl-compatible string syntax
1476
1477    $value =~ s/(["\\\$])/\\$1/g if( $self->{_escapeStrings} );
1478
1479    return $value if( $value =~ m{\A[\w!\@$%^&*_=+\[\]\{\}:;|<>./?"'-]+\z} ); # Barewords
1480
1481    return '"' . $value . '"'; # Must quote: whitespace, non-printable, comma, (), \, null string
1482}
1483
1484sub extensions {
1485    my $self = shift;
1486
1487    my $attributes = $self->_attributes;
1488    return () unless( defined $attributes && exists $attributes->{extensionRequest} );
1489
1490    my @present =  map { $_->{extnID} } @{$attributes->{extensionRequest}};
1491    if( $self->{_apiVersion} >= 1 ) {
1492	foreach my $ext (@present) {
1493	    $ext = $variantNames{'$' . $ext} if( exists $variantNames{'$' . $ext} );
1494	}
1495    }
1496    return @present;
1497}
1498
1499sub extensionValue {
1500    my $self = shift;
1501    my( $extensionName, $format ) = @_;
1502
1503    my $attributes = $self->_attributes;
1504    my $value;
1505    return unless( defined $attributes && exists $attributes->{extensionRequest} );
1506
1507    $extensionName = $self->_oid2name( $extensionName );
1508
1509    $extensionName = $variantNames{$extensionName} if( exists $variantNames{$extensionName} );
1510
1511    foreach my $entry (@{$attributes->{extensionRequest}}) {
1512        if ($entry->{extnID} eq $extensionName) {
1513            $value = $entry->{extnValue};
1514	    if( $self->{_apiVersion} == 0 ) {
1515		while (ref $value eq 'HASH') {
1516		    my @keys = sort keys %{$value};
1517		    $value = $value->{ shift @keys } ;
1518		}
1519	    } else {
1520		if( $entry->{_FMT} ) { # Special formatting
1521		    $value = $entry->{_FMT}[$format? 1:0];
1522		} else {
1523		    $value = $self->_hash2string( $value, '(?i:^(?:critical|.*id)$)' );
1524		    $value = $self->_value2strings( $value ) if( $format );
1525		}
1526	    }
1527	    last;
1528        }
1529    }
1530    $value =~ s/^\((.*)\)$/$1/ if( $format );
1531
1532    return $value;
1533}
1534
1535sub extensionPresent {
1536    my $self = shift;
1537    my( $extensionName ) = @_;
1538
1539    my $attributes = $self->_attributes;
1540    return unless( defined $attributes && exists $attributes->{extensionRequest} );
1541
1542    $extensionName = $self->_oid2name( $extensionName );
1543
1544    $extensionName = $variantNames{$extensionName} if( exists $variantNames{$extensionName} );
1545
1546    foreach my $entry (@{$attributes->{extensionRequest}}) {
1547        if ($entry->{extnID} eq $extensionName) {
1548	    return 2 if ($entry->{critical});
1549	    return 1;
1550        }
1551    }
1552    return;
1553}
1554
1555sub checkSignature {
1556    my $self = shift;
1557
1558    undef $error;
1559    delete $self->{_error};
1560
1561    my $ok = eval {
1562        die( "checkSignature requires API version 1\n" ) unless( $self->{_apiVersion} >= 1 );
1563
1564        my $key = $self->subjectPublicKey(1); # Key as PEM
1565        my $sig = $self->signature(1);        # Signature as DER
1566        my $alg = $self->signatureAlgorithm;  # Algorithm name
1567
1568        # Determine the signature hash type from the algorithm name
1569
1570        my( $hash, $hashmod, $hashfcn ); # hashnnn, Digest::mod, Digest::mod::fcn
1571        if( $alg =~ /sha-?(\d+)/i ) {
1572            $hash = "sha$1";
1573            $hashmod = 'Digest::SHA';
1574            $hashfcn = "Digest::SHA::$hash";
1575        } elsif( $alg =~ /md-?(\d)/i ) {
1576            $hash = "md$1";
1577            $hashmod = "Digest::MD$1";
1578            $hashfcn = "Digest::MD$1::$hash";
1579        } else {
1580            die( "Unknown hash in signature algorithm $alg\n" );
1581        }
1582
1583        my $keyp = $self->subjectPublicKeyParams;
1584
1585        die( "Unknown public key type\n" ) unless( defined $keyp->{keytype} );
1586
1587        # Verify signature using the correct module and hash type.
1588
1589        if( $keyp->{keytype} eq 'RSA' ) {
1590
1591            eval { require Crypt::PK::RSA; };
1592            die( "Unable to load Crypt::PK::RSA\n" ) if( $@ );
1593
1594            $key = Crypt::PK::RSA->new( \$key );
1595            return $key->verify_message( $sig, $self->certificationRequest, uc($hash),  "v1.5" );
1596
1597        }
1598
1599        if( $keyp->{keytype} eq 'DSA' ) {
1600
1601            eval { require Crypt::PK::DSA; };
1602            die( "Unable to load Crypt::PK::DSA\n" ) if( $@ );
1603
1604            $key = Crypt::PK::DSA->new( \$key );
1605            return $key->verify_message( $sig, $self->certificationRequest, uc($hash) );
1606        }
1607
1608        if( $keyp->{keytype} eq 'ECC' ) {
1609            eval { require Crypt::PK::ECC; };
1610            die( "Unable to load Crypt::PK::ECC\n" ) if( $@ );
1611
1612            $key = Crypt::PK::ECC->new( \$key );
1613            return $key->verify_message( $sig, $self->certificationRequest, uc($hash) );
1614        }
1615
1616        die( "Unknown key type $keyp->{keytype}\n" );
1617    };
1618    if( $@ ) {
1619        $self->{_error} =
1620          $error = $@;
1621        croak( $error ) if( $self->{_dieOnError} );
1622        return;
1623    }
1624    return 1 if( $ok );
1625
1626    $self->{_error} =
1627      $error = "Incorrect signature\n";
1628    croak( $error ) if( $self->{_dieOnError} );
1629
1630    return 0;
1631}
1632
1633sub _wrap {
1634    my( $to, $text ) = @_;
1635
1636    my $wid = 76 - $to;
1637
1638    my $out = substr( $text, 0, $wid, '' );
1639
1640    while( length $text ) {
1641	$out .= "\n" . (' ' x $to) . substr( $text, 0, $wid, '' );
1642    }
1643    return $out;
1644}
1645
1646sub _encode_PEM {
1647    my $text = encode_base64( $_[0] );
1648    return $text if( length $text <= 65 );
1649    $text    =~ tr/\n//d;
1650    my $out  = '';
1651    $out    .= substr( $text, 0, 64, '' ) . "\n" while( length $text );
1652    return   $out;
1653}
1654
1655sub as_string {
1656    my $self = shift;
1657
1658    local $self->{_escapeStrings} = 0;
1659    local( $@, $_, $! );
1660
1661    my $v = $apiVersion;
1662    ref( $self )->setAPIversion( 1 ) unless( defined $v && $v == 1 );
1663
1664    my $string = eval {
1665        $self = ref( $self )->new( $self->{_der}, acceptPEM => 0, verifySignature => 0, escapeStrings => 0 );
1666        return $error if( !defined $self );
1667
1668        $self->__stringify;
1669    };
1670    my $at = $@;
1671    ref( $self )->setAPIversion( $v ) unless( defined $v && $v == 1 );
1672
1673    $string = '' unless( defined $string );
1674    $string .= $at if( $at );
1675
1676    return $string;
1677}
1678
1679sub __stringify {
1680    my $self = shift;
1681
1682    my $max = 0;
1683    foreach ($self->attributes, $self->extensions,
1684	     qw/Version Subject Key_algorithm Public_key Signature_algorithm Signature/) {
1685	$max = length if( length > $max );
1686    }
1687
1688    my $string = sprintf( "%-*s: %s\n", $max, 'Version', $self->version ) ;
1689
1690    $string .= sprintf( "%-*s: %s\n", $max, 'Subject', _wrap( $max+2, scalar $self->subject ) );
1691
1692    $string .= "\n          --Attributes--\n";
1693
1694    $string .= "     --None--" unless( $self->attributes );
1695
1696    foreach ($self->attributes) {
1697	$string .= sprintf( "%-*s: %s\n", $max, $_, _wrap( $max+2, scalar $self->attributes($_) ) );
1698    }
1699
1700    $string .= "\n          --Extensions--\n";
1701
1702    $string .= "     --None--" unless( $self->extensions );
1703
1704    foreach ($self->extensions) {
1705	my $critical = $self->extensionPresent($_) == 2? 'critical,': '';
1706
1707	$string .= sprintf( "%-*s: %s\n", $max, $_,
1708			    _wrap( $max+2, $critical . ($_ eq 'subjectAltName'?
1709							scalar $self->subjectAltName:
1710							$self->extensionValue($_, 1) ) ) );
1711    }
1712
1713    $string .= "\n          --Key and signature--\n";
1714    $string .= sprintf( "%-*s: %s\n", $max, 'Key algorithm', $self->pkAlgorithm );
1715    $string .= sprintf( "%-*s: %s\n", $max, 'Public key', _wrap( $max+2, $self->subjectPublicKey ) );
1716    $string .= $self->subjectPublicKey(1);
1717    my $kp = $self->subjectPublicKeyParams(1);
1718    foreach (sort keys %$kp) {
1719        my $v = $kp->{$_};
1720
1721        if( !defined $v && !defined( $v = $self->error ) ) {
1722            $v = 'undef';
1723        } elsif( ref $v ) {
1724            next;
1725        }
1726        $string .= sprintf( "%-*s: %s\n", $max, $_, _wrap( $max+2, $v ) );
1727    }
1728    if( exists $kp->{detail} ) {
1729        $kp = $kp->{detail};
1730        $string .= "Key details\n-----------\n";
1731        foreach (sort keys %$kp) {
1732            next if( ref $kp->{$_} );
1733            $string .= sprintf( "%-*s: %s\n", $max, $_, _wrap( $max+2, $kp->{$_} ) );
1734        }
1735    }
1736
1737    $string .= sprintf( "\n%-*s: %s\n", $max, 'Signature algorithm', $self->signatureAlgorithm );
1738    $string .= sprintf( "%-*s: %s\n", $max, 'Signature', _wrap( $max+2, $self->signature ) );
1739    my $sp = $self->signature(2);
1740    if( $sp ) {
1741        foreach (sort keys %$sp) {
1742            my $v = $sp->{$_};
1743
1744            if( ref $v ) {
1745                if( $v->can('as_hex') ) {
1746                    $v = substr( $v->as_hex, 2 );
1747                } else {
1748                    next;
1749                }
1750            }
1751            $string .= sprintf( "%-*s: %s\n", $max, $_, _wrap( $max+2, $v ) );
1752        }
1753    }
1754
1755    $string .= "\n          --Request--\n" . $self->csrRequest(1);
1756
1757    return $string;
1758}
1759
17601;
1761
1762__END__
1763
1764=encoding utf-8
1765
1766=pod
1767
1768=begin :readme
1769
1770  This file is automatically generated by pod2readme from PKCS10.pm and Changes.
1771
1772=end :readme
1773
1774=head1 NAME
1775
1776Crypt::PKCS10 - parse PKCS #10 certificate requests
1777
1778=begin :readme
1779
1780=head1 RELEASE NOTES
1781
1782Version 1.4 made several API changes.  Most users should have a painless migration.
1783
1784ALL users must call Crypt::PKCS10->setAPIversion.  If not, a warning will be generated
1785by the first class method called.  This warning will be made a fatal exception in a
1786future release.
1787
1788Other than that requirement, the legacy mode is compatible with previous versions.
1789
1790C<new> will no longer generate exceptions.  C<undef> is returned on all errors. Use
1791the error class method to retrieve the reason.
1792
1793new will accept an open file handle in addition to a request.
1794
1795Users are encouraged to migrate to the version 1 API.  It is much easier to use,
1796and does not require the application to navigate internal data structures.
1797
1798Version 1.7 provides support for DSA and ECC public keys.  By default, it verifies
1799the signature of CSRs.  It also allows the caller to verify the signature of a CSR.
1800subjectPublicKeyParams and signatureParams provide additional information.
1801The readFile option to new() will open() a file containing a CSR by name.
1802The ignoreNonBase64 option allows PEM to contain extraneous characters.
1803F<Changes> describes additional improvements.  Details follow.
1804
1805=head1 INSTALLATION
1806
1807C<Crypt::PKCS10> supports DSA, RSA and ECC public keys in CSRs.
1808
1809It depends on C<Crypt::PK::*> (provided by CryptX) for some operations.
1810All are recommended. Some methods will return errors if
1811Crypt::PKCS10 is presented with a CSR containing an unsupported public key type.
1812
1813To install this module type the following:
1814
1815    perl Makefile.PL
1816    make
1817    make test
1818    make install
1819
1820=head1 REQUIRES
1821
1822C<Convert::ASN1>
1823
1824C<Crypt::PK::DSA>
1825
1826C<Crypt::PK::RSA>
1827
1828C<Crypt::PK::ECC>
1829
1830C<Digest::SHA>
1831
1832Very old CSRs may require C<DIGEST::MD{5,4,2}>
1833
1834=end :readme
1835
1836=head1 SYNOPSIS
1837
1838    use Crypt::PKCS10;
1839
1840    Crypt::PKCS10->setAPIversion( 1 );
1841    my $decoded = Crypt::PKCS10->new( $csr ) or die Crypt::PKCS10->error;
1842
1843    print $decoded;
1844
1845    @names = $decoded->extensionValue('subjectAltName' );
1846    @names = $decoded->subject unless( @names );
1847
1848    %extensions = map { $_ => $decoded->extensionValue( $_ ) } $decoded->extensions
1849
1850=head1 DESCRIPTION
1851
1852C<Crypt::PKCS10> parses PKCS #10 certificate requests (CSRs) and provides accessor methods to extract the data in usable form.
1853
1854Common object identifiers will be translated to their corresponding names.
1855Additionally, accessor methods allow extraction of single data fields.
1856The format of returned data varies by accessor.
1857
1858The access methods return the value corresponding to their name.  If called in scalar context, they return the first value (or an empty string).  If called in array context, they return all values.
1859
1860B<true> values should be specified as 1 and B<false> values as 0.  Future API changes may provide different functions when other values are used.
1861
1862=head1 METHODS
1863
1864Access methods may exist for subject name components that are not listed here.  To test for these, use code of the form:
1865
1866  $locality = $decoded->localityName if( $decoded->can('localityName') );
1867
1868If a name component exists in a CSR, the method will be present.  The converse is not (always) true.
1869
1870=head2 class method setAPIversion( $version )
1871
1872Selects the API version (0 or 1) expected.
1873
1874Must be called before calling any other method.
1875
1876The API version determines how a CSR is parsed.  Changing the API version after
1877parsing a CSR will cause accessors to produce unpredictable results.
1878
1879=over 4
1880
1881=item Version 0 - B<DEPRECATED>
1882
1883Some OID names have spaces and descriptions
1884
1885This is the format used for C<Crypt::PKCS10> version 1.3 and lower.  The attributes method returns legacy data.
1886
1887Some new API functions are disabled.
1888
1889=item Version 1
1890
1891OID names from RFCs - or at least compatible with OpenSSL and ASN.1 notation.  The attributes method conforms to version 1.
1892
1893=back
1894
1895If not called, a warning will be generated and the API will default to version 0.
1896
1897In a future release, the warning will be changed to a fatal exception.
1898
1899To ease migration, both old and new names are accepted by the API.
1900
1901Every program should call C<setAPIversion(1)>.
1902
1903=cut
1904
1905=head2 class method getAPIversion
1906
1907Returns the current API version.
1908
1909Returns C<undef> if setAPIversion has never been called.
1910
1911=head2 class method new( $csr, %options )
1912
1913Constructor, creates a new object containing the parsed PKCS #10 certificate request.
1914
1915C<$csr> may be a scalar containing the request, a file name, or a file handle from which to read it.
1916
1917If a file name is specified, the C<readFile> option must be specified.
1918
1919If a file handle is supplied, the caller should specify C<< acceptPEM => 0 >> if the contents are DER.
1920
1921The request may be PEM or binary DER encoded.  Only one request is processed.
1922
1923If PEM, other data (such as mail headers) may precede or follow the CSR.
1924
1925    my $decoded = Crypt::PKCS10->new( $csr ) or die Crypt::PKCS10->error;
1926
1927Returns C<undef> if there is an I/O error or the request can not be parsed successfully.
1928
1929Call C<error()> to obtain more detail.
1930
1931=head3 options
1932
1933The options are specified as C<< name => value >>.
1934
1935If the first option is a HASHREF, it is expanded and any remaining options are added.
1936
1937=over 4
1938
1939=item acceptPEM
1940
1941If B<false>, the input must be in DER format.  C<binmode> will be called on a file handle.
1942
1943If B<true>, the input is checked for a C<CERTIFICATE REQUEST> header.  If not found, the csr
1944is assumed to be in DER format.
1945
1946Default is B<true>.
1947
1948=item PEMonly
1949
1950If B<true>, the input must be in PEM format.  An error will be returned if the input doesn't contain a C<CERTIFICATE REQUEST> header.
1951If B<false>, the input is parsed according to C<acceptPEM>.
1952
1953Default is B<false>.
1954
1955=item binaryMode
1956
1957If B<true>, an input file or file handle will be set to binary mode prior to reading.
1958
1959If B<false>, an input file or file handle's C<binmode> will not be modified.
1960
1961Defaults to B<false> if B<acceptPEM> is B<true>, otherwise B<true>.
1962
1963=item dieOnError
1964
1965If B<true>, any API function that sets an error string will also C<die>.
1966
1967If B<false>, exceptions are only generated for fatal conditions.
1968
1969The default is B<false>.  API version 1 only..
1970
1971=item escapeStrings
1972
1973If B<true>, strings returned for extension and attribute values are '\'-escaped when formatted.
1974This is compatible with OpenSSL configuration files.
1975
1976The special characters are: '\', '$', and '"'
1977
1978If B<false>, these strings are not '\'-escaped.  This is useful when they are being displayed
1979to a human.
1980
1981The default is B<true>.
1982
1983=item ignoreNonBase64
1984
1985If B<true>, most invalid base64 characters in PEM data will be ignored.  For example, this will
1986accept CSRs prefixed with '> ', as e-mail when the PEM is inadvertently quoted.  Note that the
1987BEGIN and END lines may not be corrupted.
1988
1989If B<false>, invalid base64 characters in PEM data will cause the CSR to be rejected.
1990
1991The default is B<false>.
1992
1993=item readFile
1994
1995If B<true>, C<$csr> is the name of a file containing the CSR.
1996
1997If B<false>, C<$csr> contains the CSR or is an open file handle.
1998
1999The default is B<false>.
2000
2001=item verifySignature
2002
2003If B<true>, the CSR's signature is checked.  If verification fails, C<new> will fail.  Requires API version 1.
2004
2005If B<false>, the CSR's signature is not checked.
2006
2007The default is B<true> for API version 1 and B<false> for API version 0.
2008
2009See C<checkSignature> for requirements and limitations.
2010
2011=back
2012
2013No exceptions are generated, unless C<dieOnError> is set or C<new()> is called in
2014void context.
2015
2016The defaults will accept either PEM or DER from a string or file hande, which will
2017not be set to binary mode.  Automatic detection of the data format may not be
2018reliable on file systems that represent text and binary files differently. Set
2019C<acceptPEM> to B<false> and C<PEMonly> to match the file type on these systems.
2020
2021The object will stringify to a human-readable representation of the CSR.  This is
2022useful for debugging and perhaps for displaying a request.  However, the format
2023is not part of the API and may change.  It should not be parsed by automated tools.
2024
2025Exception: The public key and extracted request are PEM blocks, which other tools
2026can extract.
2027
2028If another object inherits from C<Crypt::PKCS10>, it can extend the representation
2029by overloading or calling C<as_string>.
2030
2031=head2 {class} method error
2032
2033Returns a string describing the last error encountered;
2034
2035If called as an instance method, last error encountered by the object.
2036
2037If called as a class method, last error encountered by the class.
2038
2039Any method can reset the string to B<undef>, so the results are
2040only valid immediately after a method call.
2041
2042=head2 class method name2oid( $oid )
2043
2044Returns the OID corresponding to a name returned by an access method.
2045
2046Not in API v0;
2047
2048=head2 csrRequest( $format )
2049
2050Returns the binary (ASN.1) request (after conversion from PEM and removal of any data beyond the length of the ASN.1 structure.
2051
2052If $format is B<true>, the request is returned as a PEM CSR.  Otherwise as a binary string.
2053
2054=head2 certificationRequest
2055
2056Returns the binary (ASN.1) section of the request that is signed by the requestor.
2057
2058The caller can verify the signature using B<signatureAlgorithm>, B<certificationRequest> and B<signature(1)>.
2059
2060=head2 Access methods for the subject's distinguished name
2061
2062Note that B<subjectAltName> is prefered, and that modern certificate users will ignore the subject if B<subjectAltName> is present.
2063
2064=head3 subject( $format )
2065
2066Returns the entire subject of the CSR.
2067
2068In scalar context, returns the subject as a string in the form C</componentName=value,value>.
2069  If format is B<true>, long component names are used.  By default, abbreviations are used when they exist.
2070
2071  e.g. /countryName=AU/organizationalUnitName=Big org/organizationalUnitName=Smaller org
2072  or     /C=AU/OU=Big org/OU=Smaller org
2073
2074In array context, returns an array of C<(componentName, [values])> pairs.  Abbreviations are not used.
2075
2076Note that the order of components in a name is significant.
2077
2078
2079=head3 subjectRaw
2080
2081Returns the subjects RDNs as sequence of hashes without OID any mapping applied.
2082
2083The result is an array ref where each item is a hash:
2084
2085    [
2086        {
2087        'format' => 'ia5String',
2088        'value' => 'Org',
2089        'type' => '0.9.2342.19200300.100.1.25'
2090        },
2091        {
2092        'format' => 'utf8String',
2093        'value' => 'ACME',
2094        'type' => '2.5.4.10'
2095        },
2096        {
2097        'format' => 'utf8String',
2098        'type' => '2.5.4.3',
2099        'value' => 'Foobar'
2100        }
2101    ]
2102
2103If a component contains a SET, the component will become an array on the
2104second level, too:
2105
2106    [
2107        {
2108        'format' => 'ia5String',
2109        'value' => 'Org',
2110        'type' => '0.9.2342.19200300.100.1.25'
2111        },
2112        {
2113        'format' => 'utf8String',
2114        'value' => 'ACME',
2115        'type' => '2.5.4.10'
2116        },
2117        [
2118            {
2119                'format' => 'utf8String',
2120                'type' => '2.5.4.3',
2121                'value' => 'Foobar'
2122            },
2123            {
2124                'format' => 'utf8String',
2125                'type' => '0.9.2342.19200300.100.1.1',
2126                'value' => 'foobar'
2127            }
2128        ]
2129    ];
2130
2131=head3 commonName
2132
2133Returns the common name(s) from the subject.
2134
2135    my $cn = $decoded->commonName();
2136
2137=head3 organizationalUnitName
2138
2139Returns the organizational unit name(s) from the subject
2140
2141=head3 organizationName
2142
2143Returns the organization name(s) from the subject.
2144
2145=head3 emailAddress
2146
2147Returns the email address from the subject.
2148
2149=head3 stateOrProvinceName
2150
2151Returns the state or province name(s) from the subject.
2152
2153=head3 countryName
2154
2155Returns the country name(s) from the subject.
2156
2157=head2 subjectAltName( $type )
2158
2159Convenience method.
2160
2161When $type is specified: returns the subject alternate name values of the specified type in list context, or the first value
2162of the specified type in scalar context.
2163
2164Returns undefined/empty list if no values of the specified type are present, or if the B<subjectAltName>
2165extension is not present.
2166
2167Types can be any of:
2168
2169   otherName
2170 * rfc822Name
2171 * dNSName
2172   x400Address
2173   directoryName
2174   ediPartyName
2175 * uniformResourceIdentifier
2176 * iPAddress
2177 * registeredID
2178
2179The types marked with '*' are the most common.
2180
2181If C<$type> is not specified:
2182 In list context returns the types present in the subjectAlternate name.
2183 In scalar context, returns the SAN as a string.
2184
2185=head2 version
2186
2187Returns the structure version as a string, e.g. "v1" "v2", or "v3"
2188
2189=head2 pkAlgorithm
2190
2191Returns the public key algorithm according to its object identifier.
2192
2193=head2 subjectPublicKey( $format )
2194
2195If C<$format> is B<true>, the public key will be returned in PEM format.
2196
2197Otherwise, the public key will be returned in its hexadecimal representation
2198
2199=head2 subjectPublicKeyParams
2200
2201Returns a hash describing the public key.  The contents vary depending on
2202the public key type.
2203
2204=head3 Standard items:
2205
2206C<keytype> - ECC, RSA, DSA or C<undef>
2207
2208C<keytype> will be C<undef> if the key type is not supported.  In
2209this case, C<error()> returns a diagnostic message.
2210
2211C<keylen> - Approximate length of the key in bits.
2212
2213Other items include:
2214
2215For RSA, C<modulus> and C<publicExponent>.
2216
2217For DSA, C<G, P and Q>.
2218
2219For ECC, C<curve>, C<pub_x> and C<pub_y>.  C<curve> is an OID name.
2220
2221=head3 Additional detail
2222
2223C<subjectPublicKeyParams(1)> returns the standard items, and may
2224also return C<detail>, which is a hashref.
2225
2226For ECC, the C<detail> hash includes the curve definition constants.
2227
2228=head2 signatureAlgorithm
2229
2230Returns the signature algorithm according to its object identifier.
2231
2232=head2 signatureParams
2233
2234Returns the parameters associated with the B<signatureAlgorithm> as binary.
2235Returns B<undef> if none, or if B<NULL>.
2236
2237Note: In the future, some B<signatureAlgorithm>s may return a hashref of decoded fields.
2238
2239Callers are advised to check for a ref before decoding...
2240
2241=head2 signature( $format )
2242
2243The CSR's signature is returned.
2244
2245If C<$format> is B<1>, in binary.
2246
2247If C<$format> is B<2>, decoded as an ECDSA signature - returns hashref to C<r> and C<s>.
2248
2249Otherwise, in its hexadecimal representation.
2250
2251=head2 attributes( $name )
2252
2253A request may contain a set of attributes. The attributes are OIDs with values.
2254The most common is a list of requested extensions, but other OIDs can also
2255occur.  Of those, B<challengePassword> is typical.
2256
2257For API version 0, this method returns a hash consisting of all
2258attributes in an internal format.  This usage is B<deprecated>.
2259
2260For API version 1:
2261
2262If $name is not specified, a list of attribute names is returned.  The list does not
2263include the requestedExtensions attribute.  For that, use extensions();
2264
2265If no attributes are present, the empty list (C<undef> in scalar context) is returned.
2266
2267If $name is specified, the value of the extension is returned.  $name can be specified
2268as a numeric OID.
2269
2270In scalar context, a single string is returned, which may include lists and labels.
2271
2272  cspName="Microsoft Strong Cryptographic Provider",keySpec=2,signature=("",0)
2273
2274Special characters are escaped as described in options.
2275
2276In array context, the value(s) are returned as a list of items, which may be references.
2277
2278 print( " $_: ", scalar $decoded->attributes($_), "\n" )
2279                                   foreach ($decoded->attributes);
2280
2281
2282=for readme stop
2283
2284See the I<Table of known OID names> below for a list of names.
2285
2286=for readme continue
2287
2288=begin :readme
2289
2290See the module documentation for a list of known OID names.
2291
2292It is too long to include here.
2293
2294=end :readme
2295
2296=head2 extensions
2297
2298Returns an array containing the names of all extensions present in the CSR.  If no extensions are present,
2299the empty list is returned.
2300
2301The names vary depending on the API version; however, the returned names are acceptable to C<extensionValue>, C<extensionPresent>, and C<name2oid>.
2302
2303The values of extensions vary, however the following code fragment will dump most extensions and their value(s).
2304
2305 print( "$_: ", $decoded->extensionValue($_,1), "\n" ) foreach ($decoded->extensions);
2306
2307
2308The sample code fragment is not guaranteed to handle all cases.
2309Production code needs to select the extensions that it understands and should respect
2310the B<critical> boolean.  B<critical> can be obtained with extensionPresent.
2311
2312=head2 extensionValue( $name, $format )
2313
2314Returns the value of an extension by name, e.g. C<extensionValue( 'keyUsage' )>.
2315The name SHOULD be an API v1 name, but API v0 names are accepted for compatibility.
2316The name can also be specified as a numeric OID.
2317
2318If C<$format> is 1, the value is a formatted string, which may include lists and labels.
2319Special characters are escaped as described in options;
2320
2321If C<$format> is 0 or not defined, a string, or an array reference may be returned.
2322The array many contain any Perl variable type.
2323
2324To interpret the value(s), you need to know the structure of the OID.
2325
2326=for readme stop
2327
2328See the I<Table of known OID names> below for a list of names.
2329
2330=for readme continue
2331
2332=begin :readme
2333
2334See the module documentation for a list of known OID names.
2335
2336It is too long to include here.
2337
2338=end :readme
2339
2340=head2 extensionPresent( $name )
2341
2342Returns B<true> if a named extension is present:
2343    If the extension is B<critical>, returns 2.
2344    Otherwise, returns 1, indicating B<not critical>, but present.
2345
2346If the extension is not present, returns C<undef>.
2347
2348The name can also be specified as a numeric OID.
2349
2350=for readme stop
2351
2352See the I<Table of known OID names> below for a list of names.
2353
2354=for readme continue
2355
2356=begin :readme
2357
2358See the module documentation for a list of known OID names.
2359
2360It is too long to include here.
2361
2362=end :readme
2363
2364=head2 registerOID( )
2365
2366Class method.
2367
2368Register a custom OID, or a public OID that has not been added to Crypt::PKCS10 yet.
2369
2370The OID may be an extension identifier or an RDN component.
2371
2372The oid is specified as a string in numeric form, e.g. C<'1.2.3.4'>
2373
2374=head3 registerOID( $oid )
2375
2376Returns B<true> if the specified OID is registered, B<false> otherwise.
2377
2378=head3 registerOID( $oid, $longname, $shortname )
2379
2380Registers the specified OID with the associated long name.  This
2381enables the OID to be translated to a name in output.
2382
2383The long name should be Hungarian case (B<commonName>), but this is not currently
2384enforced.
2385
2386Optionally, specify the short name used for extracting the subject.
2387The short name should be upper-case (and will be upcased).
2388
2389E.g. built-in are C<< $oid => '2.4.5.3', $longname => 'commonName', $shortname => 'CN' >>
2390
2391To register a shortname for an existing OID without one, specify C<$longname> as C<undef>.
2392
2393E.g. To register /E for emailAddress, use:
2394  C<< Crypt::PKCS10->registerOID( '1.2.840.113549.1.9.1', undef, 'e' ) >>
2395
2396
2397Generates an exception if any argument is not valid, or is in use.
2398
2399Returns B<true> otherwise.
2400
2401=head2 checkSignature
2402
2403Verifies the signature of a CSR.  (Useful if new() specified C<< verifySignature => 0 >>.)
2404
2405Returns B<true> if the signature is OK.
2406
2407Returns B<false> if the signature is incorrect.  C<< error() >> returns
2408the reason.
2409
2410Returns B<undef> if it was not possible to complete the verification process (e.g. a required
2411Perl module could not be loaded or an unsupported key/signature type is present.)
2412
2413I<Note>: Requires Crypt::PK::* for the used algorithm to be installed. For RSA
2414v1.5 padding is assumed, PSS is not supported (validation fails).
2415
2416
2417=head2 certificateTemplate
2418
2419C<CertificateTemplate> returns the B<certificateTemplate> attribute.
2420
2421Equivalent to C<extensionValue( 'certificateTemplate' )>, which is prefered.
2422
2423=for readme stop
2424
2425=head2 Table of known OID names
2426
2427The following OID names are known.  They are used in returned strings and
2428structures, and as names by methods such as B<extensionValue>.
2429
2430Unknown OIDs are returned in numeric form, or can be registered with
2431B<registerOID>.
2432
2433=begin MAINTAINER
2434
2435 To generate the following table, use:
2436    perl -Mwarnings -Mstrict -MCrypt::PKCS10 -e'Crypt::PKCS10->_listOIDs'
2437
2438=end MAINTAINER
2439
2440 OID                        Name (API v1)              Old Name (API v0)
2441 -------------------------- -------------------------- ---------------------------
2442 0.9.2342.19200300.100.1.1  userID
2443 0.9.2342.19200300.100.1.25 domainComponent
2444 1.2.840.10040.4.1          dsa                        (DSA)
2445 1.2.840.10040.4.3          dsaWithSha1                (DSA with SHA1)
2446 1.2.840.10045.2.1          ecPublicKey
2447 1.2.840.10045.3.1.1        secp192r1
2448 1.2.840.10045.3.1.7        secp256r1
2449 1.2.840.10045.4.3.1        ecdsa-with-SHA224
2450 1.2.840.10045.4.3.2        ecdsa-with-SHA256
2451 1.2.840.10045.4.3.3        ecdsa-with-SHA384
2452 1.2.840.10045.4.3.4        ecdsa-with-SHA512
2453 1.2.840.113549.1.1.1       rsaEncryption              (RSA encryption)
2454 1.2.840.113549.1.1.2       md2WithRSAEncryption       (MD2 with RSA encryption)
2455 1.2.840.113549.1.1.3       md4WithRSAEncryption
2456 1.2.840.113549.1.1.4       md5WithRSAEncryption       (MD5 with RSA encryption)
2457 1.2.840.113549.1.1.5       sha1WithRSAEncryption      (SHA1 with RSA encryption)
2458 1.2.840.113549.1.1.6       rsaOAEPEncryptionSET
2459 1.2.840.113549.1.1.7       RSAES-OAEP
2460 1.2.840.113549.1.1.11      sha256WithRSAEncryption    (SHA-256 with RSA encryption)
2461 1.2.840.113549.1.1.12      sha384WithRSAEncryption
2462 1.2.840.113549.1.1.13      sha512WithRSAEncryption    (SHA-512 with RSA encryption)
2463 1.2.840.113549.1.1.14      sha224WithRSAEncryption
2464 1.2.840.113549.1.9.1       emailAddress
2465 1.2.840.113549.1.9.2       unstructuredName
2466 1.2.840.113549.1.9.7       challengePassword
2467 1.2.840.113549.1.9.14      extensionRequest
2468 1.2.840.113549.1.9.15      smimeCapabilities          (SMIMECapabilities)
2469 1.3.6.1.4.1.311.2.1.14     CERT_EXTENSIONS
2470 1.3.6.1.4.1.311.2.1.21     msCodeInd
2471 1.3.6.1.4.1.311.2.1.22     msCodeCom
2472 1.3.6.1.4.1.311.10.3.1     msCTLSign
2473 1.3.6.1.4.1.311.10.3.2     msTimeStamping
2474 1.3.6.1.4.1.311.10.3.3     msSGC
2475 1.3.6.1.4.1.311.10.3.4     msEFS
2476 1.3.6.1.4.1.311.10.3.4.1   msEFSRecovery
2477 1.3.6.1.4.1.311.10.3.5     msWHQLCrypto
2478 1.3.6.1.4.1.311.10.3.6     msNT5Crypto
2479 1.3.6.1.4.1.311.10.3.7     msOEMWHQLCrypto
2480 1.3.6.1.4.1.311.10.3.8     msEmbeddedNTCrypto
2481 1.3.6.1.4.1.311.10.3.9     msRootListSigner
2482 1.3.6.1.4.1.311.10.3.10    msQualifiedSubordination
2483 1.3.6.1.4.1.311.10.3.11    msKeyRecovery
2484 1.3.6.1.4.1.311.10.3.12    msDocumentSigning
2485 1.3.6.1.4.1.311.10.3.13    msLifetimeSigning
2486 1.3.6.1.4.1.311.10.3.14    msMobileDeviceSoftware
2487 1.3.6.1.4.1.311.13.1       RENEWAL_CERTIFICATE
2488 1.3.6.1.4.1.311.13.2.1     ENROLLMENT_NAME_VALUE_PAIR
2489 1.3.6.1.4.1.311.13.2.2     ENROLLMENT_CSP_PROVIDER
2490 1.3.6.1.4.1.311.13.2.3     OS_Version
2491 1.3.6.1.4.1.311.20.2       certificateTemplateName
2492 1.3.6.1.4.1.311.20.2.2     msSmartCardLogon
2493 1.3.6.1.4.1.311.21.7       certificateTemplate
2494 1.3.6.1.4.1.311.21.10      ApplicationCertPolicies
2495 1.3.6.1.4.1.311.21.20      ClientInformation
2496 1.3.6.1.5.2.3.5            keyPurposeKdc              (KDC Authentication)
2497 1.3.6.1.5.5.7.2.1          CPS
2498 1.3.6.1.5.5.7.2.2          userNotice
2499 1.3.6.1.5.5.7.3.1          serverAuth
2500 1.3.6.1.5.5.7.3.2          clientAuth
2501 1.3.6.1.5.5.7.3.3          codeSigning
2502 1.3.6.1.5.5.7.3.4          emailProtection
2503 1.3.6.1.5.5.7.3.8          timeStamping
2504 1.3.6.1.5.5.7.3.9          OCSPSigning
2505 1.3.6.1.5.5.7.3.21         sshClient
2506 1.3.6.1.5.5.7.3.22         sshServer
2507 1.3.6.1.5.5.7.9.5          countryOfResidence
2508 1.3.14.3.2.29              sha1WithRSAEncryption      (SHA1 with RSA signature)
2509 1.3.36.3.3.2.8.1.1.1       brainpoolP160r1
2510 1.3.36.3.3.2.8.1.1.2       brainpoolP160t1
2511 1.3.36.3.3.2.8.1.1.3       brainpoolP192r1
2512 1.3.36.3.3.2.8.1.1.4       brainpoolP192t1
2513 1.3.36.3.3.2.8.1.1.5       brainpoolP224r1
2514 1.3.36.3.3.2.8.1.1.6       brainpoolP224t1
2515 1.3.36.3.3.2.8.1.1.7       brainpoolP256r1
2516 1.3.36.3.3.2.8.1.1.8       brainpoolP256t1
2517 1.3.36.3.3.2.8.1.1.9       brainpoolP320r1
2518 1.3.36.3.3.2.8.1.1.10      brainpoolP320t1
2519 1.3.36.3.3.2.8.1.1.11      brainpoolP384r1
2520 1.3.36.3.3.2.8.1.1.12      brainpoolP384t1
2521 1.3.36.3.3.2.8.1.1.13      brainpoolP512r1
2522 1.3.36.3.3.2.8.1.1.14      brainpoolP512t1
2523 1.3.132.0.1                sect163k1
2524 1.3.132.0.15               sect163r2
2525 1.3.132.0.16               sect283k1
2526 1.3.132.0.17               sect283r1
2527 1.3.132.0.26               sect233k1
2528 1.3.132.0.27               sect233r1
2529 1.3.132.0.33               secp224r1
2530 1.3.132.0.34               secp384r1
2531 1.3.132.0.35               secp521r1
2532 1.3.132.0.36               sect409k1
2533 1.3.132.0.37               sect409r1
2534 1.3.132.0.38               sect571k1
2535 1.3.132.0.39               sect571r1
2536 2.5.4.3                    commonName
2537 2.5.4.4                    surname                    (Surname)
2538 2.5.4.5                    serialNumber
2539 2.5.4.6                    countryName
2540 2.5.4.7                    localityName
2541 2.5.4.8                    stateOrProvinceName
2542 2.5.4.9                    streetAddress
2543 2.5.4.10                   organizationName
2544 2.5.4.11                   organizationalUnitName
2545 2.5.4.12                   title                      (Title)
2546 2.5.4.13                   description                (Description)
2547 2.5.4.14                   searchGuide
2548 2.5.4.15                   businessCategory
2549 2.5.4.16                   postalAddress
2550 2.5.4.17                   postalCode
2551 2.5.4.18                   postOfficeBox
2552 2.5.4.19                   physicalDeliveryOfficeName
2553 2.5.4.20                   telephoneNumber
2554 2.5.4.23                   facsimileTelephoneNumber
2555 2.5.4.41                   name                       (Name)
2556 2.5.4.42                   givenName
2557 2.5.4.43                   initials
2558 2.5.4.44                   generationQualifier
2559 2.5.4.45                   uniqueIdentifier
2560 2.5.4.46                   dnQualifier
2561 2.5.4.51                   houseIdentifier
2562 2.5.4.65                   pseudonym
2563 2.5.29.14                  subjectKeyIdentifier       (SubjectKeyIdentifier)
2564 2.5.29.15                  keyUsage                   (KeyUsage)
2565 2.5.29.17                  subjectAltName
2566 2.5.29.19                  basicConstraints           (Basic Constraints)
2567 2.5.29.32                  certificatePolicies
2568 2.5.29.32.0                anyPolicy
2569 2.5.29.37                  extKeyUsage                (EnhancedKeyUsage)
2570 2.16.840.1.101.3.4.2.1     sha256                     (SHA-256)
2571 2.16.840.1.101.3.4.2.2     sha384                     (SHA-384)
2572 2.16.840.1.101.3.4.2.3     sha512                     (SHA-512)
2573 2.16.840.1.101.3.4.2.4     sha224                     (SHA-224)
2574 2.16.840.1.101.3.4.3.1     dsaWithSha224
2575 2.16.840.1.101.3.4.3.2     dsaWithSha256
2576 2.16.840.1.101.3.4.3.3     dsaWithSha384
2577 2.16.840.1.101.3.4.3.4     dsaWithSha512
2578 2.16.840.1.113730.1.1      netscapeCertType
2579 2.16.840.1.113730.1.2      netscapeBaseUrl
2580 2.16.840.1.113730.1.4      netscapeCaRevocationUrl
2581 2.16.840.1.113730.1.7      netscapeCertRenewalUrl
2582 2.16.840.1.113730.1.8      netscapeCaPolicyUrl
2583 2.16.840.1.113730.1.12     netscapeSSLServerName
2584 2.16.840.1.113730.1.13     netscapeComment
2585 2.16.840.1.113730.4.1      nsSGC
2586
2587=for readme continue
2588
2589=begin :readme
2590
2591=head1 CHANGES
2592
2593=for readme include file=Changes type=text start=^1\.0 stop=^__END__
2594
2595For a more detailed list of changes, see F<Commitlog> in the distribution.
2596
2597=end :readme
2598
2599=head1 EXAMPLES
2600
2601In addition to the code snippets contained in this document, the F<examples/> directory of the distribution
2602contains some sample utilitiles.
2603
2604Also, the F<t/> directory of the distribution contains a number of tests that exercise the
2605API.  Although artificial, they are another good source of examples.
2606
2607Note that the type of data returned when extracting attributes and extensions is dependent
2608on the specific OID used.
2609
2610Also note that some functions not listed in this document are tested.  The fact that they are
2611tested does not imply that they are stable, or that they will be present in any future release.
2612
2613The test data was selected to exercise the API; the CSR contents are not representative of
2614realistic certificate requests.
2615
2616=head1 ACKNOWLEDGEMENTS
2617
2618Martin Bartosch contributed preliminary EC support:  OIDs and tests.
2619
2620Timothe Litt made most of the changes for V1.4+
2621
2622C<Crypt::PKCS10> is based on the generic ASN.1 module by Graham Barr and on the
2623 x509decode example by Norbert Klasen. It is also based upon the
2624works of Duncan Segrest's C<Crypt-X509-CRL> module.
2625
2626=head1 AUTHORS
2627
2628Gideon Knocke <gknocke@cpan.org>
2629Timothe Litt <tlhackque@cpan.org>
2630
2631=head1 LICENSE
2632
2633GPL v1 -- See LICENSE file for details
2634
2635=cut
2636