X500-DN-0.29/0000755000175000017500000000000010644212577010217 5ustar rjrjX500-DN-0.29/RDN.pod0000644000175000017500000000307610644212515011344 0ustar rjrj=head1 NAME X500::RDN - handle X.500 RDNs (Relative Distinguished Names), parse and format them =head1 SYNOPSIS use X500::RDN; my $rdn = new X500::RDN ('c'=>'DE'); my $c = $rdn->getAttributeValue ('c'); =head1 DESCRIPTION This module handles X.500 RDNs (Relative Distinguished Names). This is a supporting module for X500::DN. =head2 Methods =over 4 =item * $object = new X500::RDN ('type'=>'value', 'type'=>'value', ...); Creates an RDN object from argument pairs, each pair an attribute type and value. With more than one pair as arguments, you will get a multi-valued RDN. =item * $object->isMultivalued(); Returns whether the RDN is multi-valued. =item * $object->getAttributeTypes(); Returns the RDN's attribute types, a list of strings. =item * $object->getAttributeValue (type); Returns the RDN attribute's value. =item * $object->getRFC2253String(); Returns the RDN as a string formatted according to RFC 2253 syntax. =item * $object->getX500String(); Returns the RDN as a string formatted according to X.500 syntax. NOTE: This is a hack, there is no definition for a X.500 string syntax!? =item * $object->getOpenSSLString(); Returns the RDN as a string formatted according to one of openssl's syntaxes. Croaks on multi-valued RDNs. =back =head2 EXPORT None. =head1 BUGS =head1 AUTHOR Robert Joop Eyaph-070708@timesink.deE =head1 COPYRIGHT Copyright 2002 Robert Joop. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L. =cut X500-DN-0.29/Changes0000644000175000017500000000220010644211661011475 0ustar rjrjRevision history for Perl extension X500::DN. 0.29 added missing PREREQ_PM in Makefile.PL 0.28 force users to use ParseRFC2253 instead of ParseOpenSSL, now that we changed openssl to support '-nameopt RFC2253' everywhere. tests adjusted accordingly. 0.27 refined openssl formatter, will match its input after patch for req -subj and ca -subj sent to openssl-dev mailinglist. added a test for this format. 0.26 documentation fixes 'use 5.6.1;' because that seems to be the version that introduced the 'our' keyword 0.25 skip spaces around = sign takes 4 tests from todo list 0.23 convert test.pl to t/*.t six more tests 0.22 let the openssl parser croak on error five more tests 0.21 add parser and formatter for current openssl syntax. two more tests 0.20 fork off X500::RDN module and have X500::DN use it. add forgotten .pod files to MANIFEST add 26 more tests 0.15 stop Parse::RecDescent's automatic skipping of spaces add 14 more tests 0.05 fix ABSTRACT_FROM 0.01 Wed Apr 17 16:47:24 2002 - original version; created by h2xs 1.21 with options -AXc -n X500::DN X500-DN-0.29/t/0000755000175000017500000000000010644212577010462 5ustar rjrjX500-DN-0.29/t/rdn.t0000644000175000017500000000161007460363307011430 0ustar rjrj use strict; use Test; BEGIN { plan tests => 11 }; use X500::RDN; ok(1); # If we made it this far, we're ok. my $s; my $rdn; ### Tests for X500::RDN follow # Tests 2-5: check a single-valued RDN $rdn = new X500::RDN ('c'=>'DE'); ok (ref $rdn, 'X500::RDN'); ok ($rdn && $rdn->isMultivalued, ''); ok ($rdn && $rdn->getRFC2253String, 'c=DE'); ok ($rdn && $rdn->getX500String, 'c=DE'); # Tests 6-11: multi-valued RDN example from RFC 2253 $rdn = new X500::RDN ('OU'=>'Sales', 'CN'=>'J. Smith'); ok (ref $rdn, 'X500::RDN'); ok ($rdn && $rdn->isMultivalued, 1); ok ($rdn && $rdn->getAttributeValue ('OU'), 'Sales'); ok ($rdn && $rdn->getAttributeValue ('CN'), 'J. Smith'); $s = $rdn && $rdn->getRFC2253String; ok (sub { $s eq 'OU=Sales+CN=J. Smith' || $s eq 'CN=J. Smith+OU=Sales'}, 1); $s = $rdn && $rdn->getX500String; ok (sub { $s eq '(OU=Sales, CN=J. Smith)' || $s eq '(CN=J. Smith, OU=Sales)'}, 1); X500-DN-0.29/t/dn.t0000644000175000017500000001034607465770440011261 0ustar rjrj use strict; use Test; BEGIN { plan tests => 43, todo => [38] }; use X500::DN; ok(1); # If we made it this far, we're ok. ### Tests for X500::DN follow my $s; my $rdn; my $dn; # Tests 2-4: empty DN $dn = X500::DN->ParseRFC2253 (''); ok ($dn && $dn->getRDNs(), 0); ok ($dn && $dn->getRFC2253String(), ''); ok ($dn && $dn->getX500String(), '{}'); # Test 5-9: one RDN, RDN type is oid $dn = X500::DN->ParseRFC2253 ('1.4.9=2001'); ok ($dn && $dn->getRDNs(), 1); $rdn = $dn && $dn->getRDN (0); ok ($rdn && $rdn->getAttributeTypes(), 1); ok ($rdn && ($rdn->getAttributeTypes())[0], '1.4.9'); ok ($rdn && $rdn->getAttributeValue ('1.4.9'), '2001'); ok ($dn && $dn->getRFC2253String(), '1.4.9=2001'); # Tests 10-12: two RDNs $dn = X500::DN->ParseRFC2253 ('cn=Nemo,c=US'); ok ($dn && $dn->getRDNs(), 2); ok ($dn && $dn->getRFC2253String(), 'cn=Nemo, c=US'); ok ($dn && $dn->hasMultivaluedRDNs, 0); # Tests 13-14: three RDNs $dn = X500::DN->ParseRFC2253 ('cn=John Doe, o=Acme, c=US'); ok ($dn && $dn->getRDNs(), 3); ok ($dn && $dn->getRFC2253String(), 'cn=John Doe, o=Acme, c=US'); # Tests 15-16: escaped comma $dn = X500::DN->ParseRFC2253 ('cn=John Doe, o=Acme\\, Inc., c=US'); ok ($dn && $dn->getRDNs(), 3); ok ($dn && $dn->getRDN (1)->getAttributeValue ('o'), 'Acme, Inc.'); # Tests 17-18: escaped space $dn = X500::DN->ParseRFC2253 ('x=\\ '); ok ($dn && $dn->getRDNs(), 1); $rdn = $dn && $dn->getRDN (0); ok ($rdn && $rdn->getAttributeValue ('x'), ' '); # Tests 19-20: escaped space $dn = X500::DN->ParseRFC2253 ('x = \\ '); ok ($dn && $dn->getRDNs(), 1); $rdn = $dn && $dn->getRDN (0); ok ($rdn && $rdn->getAttributeValue ('x'), ' '); # Tests 21-22: quoted space $dn = X500::DN->ParseRFC2253 ('x=" "'); ok ($dn && $dn->getRDNs(), 1); $rdn = $dn && $dn->getRDN (0); ok ($rdn && $rdn->getAttributeValue ('x'), ' '); # Tests 21-22: quoted space $dn = X500::DN->ParseRFC2253 ('x = " "'); ok ($dn && $dn->getRDNs(), 1); $rdn = $dn && $dn->getRDN (0); ok ($rdn && $rdn->getAttributeValue ('x'), ' '); # Tests 25-27: more quoted spaces $dn = X500::DN->ParseRFC2253 ('x=\\ \\ '); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), ' '); $dn = X500::DN->ParseRFC2253 ('x=\\ \\ \\ '); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), ' '); $dn = X500::DN->ParseRFC2253 ('x=\\ \\ '); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), ' '); # Tests 28-29: commas with values $dn = X500::DN->ParseRFC2253 ('x="a,b,c"'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), 'a,b,c'); $dn = X500::DN->ParseRFC2253 ('x=d\\,e'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), 'd,e'); # Test 30: escaped #, quote and a char in hex notation $dn = X500::DN->ParseRFC2253 ('x=\\#\"\\41'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), '#"A'); # Test 31-32: bytes in hex notation $dn = X500::DN->ParseRFC2253 ('x=#616263'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), 'abc'); $dn = X500::DN->ParseRFC2253 ('x=#001AFF'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), "\0\x1a\xff"); # Test 33: more special characters $dn = X500::DN->ParseRFC2253 ('x=",=+<>#;"'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('x'), ',=+<>#;'); # Test 34: UTF-8 example from RFC 2253 $dn = X500::DN->ParseRFC2253 ('SN=Lu\C4\8Di\C4\87'); ok ($dn && $dn->getRDN (0)->getAttributeValue ('SN'), 'Lučić'); # Tests 35-39: multi-valued RDN $dn = X500::DN->ParseRFC2253 ('foo=1 + bar=2, baz=3'); ok ($dn && $dn->hasMultivaluedRDNs, 1); ok ($dn && $dn->getRDNs(), 2, 1); $rdn = $dn && $dn->getRDN (1); ok ($rdn && $rdn->getAttributeTypes(), 2); ok ($rdn && $rdn->getAttributeValue ('foo'), '1'); ok ($rdn && $rdn->getAttributeValue ('bar'), '2'); # Test 40: illegal RFC 2253 syntax $dn = X500::DN->ParseRFC2253 ('foo'); ok ($dn, undef); # Test 41: openssl formatted DN $dn = eval { X500::DN->ParseOpenSSL ('/C=DE/CN=Test') }; ok (sub { !$dn && $@ }, qr:^use 'openssl -nameopt RFC2253' and ParseRFC2253():); # Test 42: no openssl output for multi-valued RDN $dn = new X500::DN (new X500::RDN ('foo'=>1, 'bar'=>2)); $s = eval { $dn->getOpenSSLString() }; ok (sub { $dn && !defined ($s) && $@ }, qr/^openssl syntax for multi-valued RDNs is unknown/); # Test 43: produce openssl format with escapes $dn = new X500::DN (new X500::RDN ('foo'=>'bar/\\baz')); ok ($dn && $dn->getOpenSSLString(), '/foo=bar\\/\\\\baz'); X500-DN-0.29/MANIFEST0000644000175000017500000000023610644212577011351 0ustar rjrjChanges DN.pm DN.pod MANIFEST Makefile.PL RDN.pm RDN.pod README t/dn.t t/rdn.t META.yml Module meta-data (added by MakeMaker) X500-DN-0.29/DN.pod0000644000175000017500000000505210644212447011222 0ustar rjrj=head1 NAME X500::DN - handle X.500 DNs (Distinguished Names), parse and format them =head1 SYNOPSIS use X500::DN; my $dn = X500::DN->ParseRFC2253 ('cn=John Doe, o=Acme\\, Inc., c=US') or die; print $dn->getRFC2253String(), "\n"; $dn = new X500::DN (new X500::RDN ('c'=>'US'), new X500::RDN ('cn'=>'John Doe')); my $rdn0 = $dn->getRDN (0); my $c = $rdn0->getAttributeValue ('c'); =head1 NOTE The RFC 2253 syntax is I in relation to the ASN.1 SEQUENCE. So the RFC 2253 string C> has the same meaning as the X.500 string C>. The X500::DN objects keep the RDNs in X.500 order! =head1 DESCRIPTION This module handles X.500 DNs (Distinguished Names). Currently, it parses DN strings formatted according to RFC 2253 syntax into an internal format and produces RFC 2253 formatted string from it. =head2 Methods =over 4 =item * $object = new X500::DN (rdn, rdn, ...); Creates a DN object from zero or more arguments of type X500::RDN. =item * $object = X500::DN->ParseRFC2253 ('cn=John Doe, o=Acme\\, Inc., c=US'); Creates a DN object from an RFC 2253 formatted DN string notation. =item * $object->getRFC2253String(); Returns the DN as a string formatted according to RFC 2253 syntax. =item * $object->getOpenSSLString(); Returns the DN as a string formatted suitable for C and C. =item * $object->getX500String(); Returns the DN as a string formatted according to X.500 syntax. NOTE: This is a hack, there is no definition for a X.500 string syntax! =item * $object->hasMultivaluedRDNs(); Returns whether the DN contains multi-valued RDNs. =item * $object->getRDN (num); Returns the DN's RDN at position num as an X500::RDN object. num starts with 0, which will return the first RDN in ASN.1 SEQUENCE order. =item * $object->getRDNs(); Returns the DN's RDNs, a list of objects of type X500::RDN, in ASN.1 SEQUENCE order. =back =head2 EXPORT None. =head1 BUGS =over 4 =item * Due to Parse::RecDescent's greedyness, white space after attribute values gets into the parsed value. It might be possible to work around this. =back =head1 AUTHOR Robert Joop Eyaph-070708@timesink.deE =head1 COPYRIGHT Copyright 2002 Robert Joop. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L. =head1 HISTORY =over 4 =item Early 2002: First idea, discussed on comp.lang.perl.moderated =item April 2002: First public release, 0.15 =back =cut X500-DN-0.29/RDN.pm0000644000175000017500000000310610644212504011166 0ustar rjrj# Copyright (c) 2002 Robert Joop # All rights reserved. # This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. package X500::RDN; use strict; use Carp; sub new { my $class = shift; my $self = { @_ }; bless $self, $class; return $self; } sub isMultivalued { my $self = shift; return $self->getAttributeTypes() > 1; } sub getAttributeTypes { my $self = shift; return keys (%$self); } sub getAttributeValue { my $self = shift; my $type = shift; return $self->{$type}; } # internal function: quote special AttributeValue characters sub _RFC2253quoteAttributeValue { my $value = shift; $value =~ s/([,;+"\\<>])/\\$1/g; $value =~ s/( )$/\\$1/g; # space at end of string $value =~ s/^([ #])/\\$1/g; # space at beginning of string return $value; } sub getRFC2253String { my $self = shift; return join ('+', map { "$_=".&_RFC2253quoteAttributeValue ($self->{$_}); } keys (%$self)); } sub getX500String { my $self = shift; my $s = join (', ', map { "$_=".&_RFC2253quoteAttributeValue ($self->{$_}) } keys (%$self)); $s = "($s)" if ($self->isMultivalued); return $s; } # internal function: quote special AttributeValue characters sub _OpenSSLquoteAttributeValue { my $value = shift; $value =~ s/([\\\/])/\\$1/g; return $value; } sub getOpenSSLString { my $self = shift; croak "openssl syntax for multi-valued RDNs is unknown" if ($self->isMultivalued); my $key = (keys (%$self))[0]; my $s = "$key=".&_OpenSSLquoteAttributeValue ($self->{$key}); return $s; } 1; X500-DN-0.29/DN.pm0000644000175000017500000000476510644212166011064 0ustar rjrj# Copyright (c) 2002 Robert Joop # All rights reserved. # This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. package X500::DN; use 5.6.1; # the "our" keyword below needs it use strict; use Carp; use Parse::RecDescent 1.80; use X500::RDN; our $VERSION = '0.29'; my $rfc2253_grammar = q { startrule: DistinguishedName /^\\Z/ { new X500::DN (reverse (@{$item[1]})); } DistinguishedName: name(?) { @{$item[1]} > 0 ? $item[1][0] : []; } name: nameComponent(s /[,;]\\s*/) nameComponent: attributeTypeAndValue(s /\\s*\\+\\s*/) { new X500::RDN (map { @$_ } @{$item[1]}); } attributeTypeAndValue: attributeType /\\s*=\\s*/ attributeValue { [ @item[1,3] ]; } attributeType: Alpha keychar(s?) { join ('', $item[1], @{$item[2]}); } | oid keychar: Alpha | Digit | '-' #oid: rfc1779oidprefix(?) Digits(s /\\./) { join ('.', @{$item[2]}) } #rfc1779oidprefix: /oid\\./i oid: Digits(s /\\./) { join ('.', @{$item[1]}) } Digits: Digit(s) { join ('', @{$item[1]}); } attributeValue: string string: (stringchar | pair)(s) { join ('', @{$item[1]}); } | '#' hexstring { $item[2] } | '"' (pair | quotechar)(s) '"' { join ('', @{$item[2]}); } quotechar: /[^"]/ special: /[,=+<>#; ]/ pair: '\\\\' ( special | '\\\\' | '"' | hexpair ) { $item[2] } stringchar: /[^,=+<>#;\\\\"]/ hexstring: hexpair(s) { join ('', @{$item[1]}); } hexpair: /[0-9A-Fa-f]{2}/ { chr (hex ($item[1])) } Alpha: /[A-Za-z]/ Digit: /[0-9]/ }; #$::RD_TRACE = 1; #$::RD_HINT = 1; local $::RD_AUTOACTION = q{ $item[1] }; local $Parse::RecDescent::skip = undef; my $parser = new Parse::RecDescent ($rfc2253_grammar) or die "Bad RFC 2253 grammar!\n"; sub new { my $class = shift; my $self = [ @_ ]; bless $self, $class; return $self; } sub hasMultivaluedRDNs { my $self = shift; return grep { $_->isMultivalued } @$self; } sub getRDN { my $self = shift; my $i = shift; return $self->[$i]; } sub getRDNs { my $self = shift; return @$self; } sub ParseRFC2253 { my $class = shift; my $text = shift; my $self = $parser->startrule ($text); return $self; } sub ParseOpenSSL { croak "use 'openssl -nameopt RFC2253' and ParseRFC2253()"; } sub getRFC2253String { my $self = shift; return join (', ', map { $_->getRFC2253String } reverse (@{$self})); } sub getX500String { my $self = shift; return '{' . join (',', map { $_->getX500String } @{$self}) . '}'; } sub getOpenSSLString { my $self = shift; return join ('/', '', map { $_->getOpenSSLString } @{$self}); } 1; X500-DN-0.29/Makefile.PL0000644000175000017500000000077010644212474012171 0ustar rjrjuse ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'X500::DN', 'VERSION_FROM' => 'DN.pm', # finds $VERSION 'PREREQ_PM' => { 'Parse::RecDescent' => '1.80', }, ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'DN.pod', # retrieve abstract from module AUTHOR => 'Robert Joop ') : ()), ); X500-DN-0.29/README0000644000175000017500000000134110644212015011061 0ustar rjrjX500/DN version 0.29 ==================== X500::DN provides a pure perl parser and formatter for RFC 2253 style DN strings. This is a late alpha version. Known bugs: Due to Parse::RecDescent's greedyness, white space after attribute values gets into the parsed value. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: Parse::RecDescent - developed and tested with version 1.80 COPYRIGHT AND LICENCE Copyright (c) 2002 Robert Joop All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. X500-DN-0.29/META.yml0000644000175000017500000000051410644212577011470 0ustar rjrj# http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: X500-DN version: 0.29 version_from: DN.pm installdirs: site requires: Parse::RecDescent: 1.80 distribution_type: module generated_by: ExtUtils::MakeMaker version 6.30_01