File Coverage

lib/Crypt/Perl/X509/Name.pm
Criterion Covered Total %
statement 31 31 100.0
branch 3 4 75.0
condition n/a
subroutine 8 8 100.0
pod 0 1 0.0
total 42 44 95.4


line stmt bran cond sub pod time code
1             package Crypt::Perl::X509::Name;
2              
3 5     5   324 use strict;
  5         7  
  5         116  
4 5     5   24 use warnings;
  5         9  
  5         162  
5              
6             =encoding utf-8
7              
8             =head1 NAME
9              
10             Crypt::Perl::X509::Name - Representation of Distinguished Name
11              
12             =head1 SYNOPSIS
13              
14             #This encodes each key/value into separate
15             #RelativeDistinguishedName structures, as OpenSSL does by default.
16             #Unless you know otherwise, this is probably what you want.
17             #(See ENCODING below for more details.)
18             my $name = Crypt::Perl::X509::Name->new(
19             streetAddress => '...', #keys are short OID names
20             localityName => '...',
21             #...
22             );
23              
24             my $der = $name->encode();
25              
26             =head1 DISCUSSION
27              
28             This is useful to represent the Subject and Issuer parts of an
29             X.509 (i.e., SSL/TLS) certificate as well as the name portion of
30             a PCKS #10 Certificate Signing Request (CSR).
31              
32             =head1 ENCODING
33              
34             L
35             defines the C type as an ordered C of unordered Cs
36             —C objects, or “RDN”s—of key/value pairs.
37             OpenSSL defaults to having each RDN contain only one key/value
38             pair. (L) I’m unclear as to why this is,
39             but I suspect it has to do with ease of matching up C values; since
40             the RDNs are unordered, to compare one multi-value RDN against another takes
41             more work than to compare two ordered lists of single-value RDNs, which can be
42             done with a simple text equality check.
43             (cf. L)
44              
45             If you need a multi-value RDN, it can be gotten by grouping key/value pairs
46             in an array reference, thus:
47              
48             my $name = Crypt::Perl::X509::Name->new(
49              
50             #a multi-value RDN
51             [ streetAddress => '...', localityName => '...' ],
52              
53             #regular key/value pair becomes its own single-value RDN
54             stateOrProvinceName => '...',
55             );
56              
57             =head1 ABOUT C
58              
59             Note that C is
60             deprecated (cf. L,
61             L)
62             for use in X.509 certificates, but many CAs still require it as of
63             December 2016.
64              
65             =cut
66              
67 5     5   21 use parent qw( Crypt::Perl::ASN1::Encodee );
  5         6  
  5         29  
68              
69 5     5   206 use Crypt::Perl::ASN1 ();
  5         7  
  5         82  
70 5     5   1673 use Crypt::Perl::X509::RelativeDistinguishedName ();
  5         11  
  5         160  
71              
72 5     5   23 use constant ASN1 => Crypt::Perl::X509::RelativeDistinguishedName::ASN1() . <
  5         8  
  5         890  
73             RDNSequence ::= SEQUENCE OF ANY -- RelativeDistinguishedName
74              
75             Name ::= CHOICE {
76             rdnSequence RDNSequence
77             }
78             END
79              
80             #XXX TODO de-duplicate
81             *get_OID = \&Crypt::Perl::X509::RelativeDistinguishedName::get_OID;
82             *encode_string = \&Crypt::Perl::X509::RelativeDistinguishedName::encode_string;
83              
84             sub new {
85 53     53 0 203 my ($class, @inputs) = @_;
86              
87 53         114 my @seq;
88              
89 53         174 while (@inputs) {
90 74 100       1956 if (my $ref = ref $inputs[0]) {
91 12         23 my $input = shift @inputs;
92 12 50       33 die "Invalid RDN ref: $ref" if $ref ne 'ARRAY';
93 12         59 push @seq, Crypt::Perl::X509::RelativeDistinguishedName->new( @$input )->encode();
94             }
95              
96             #Legacy-ish …
97             else {
98 62         189 my ($k, $v) = splice( @inputs, 0, 2 );
99 62         316 my $rdn = Crypt::Perl::X509::RelativeDistinguishedName->new( $k, $v )->encode();
100 62         12995 push @seq, $rdn;
101             }
102             }
103              
104 53         1341 return bless \@seq, $class;
105             }
106              
107             sub _encode_params {
108 53     53   150 return { rdnSequence => [ @{ $_[0] } ] };
  53         263  
109             }
110              
111             1;