Initial Commit
This commit is contained in:
37
database/perl/vendor/lib/Convert/ASCII/Armor.pm
vendored
Normal file
37
database/perl/vendor/lib/Convert/ASCII/Armor.pm
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/perl -sw
|
||||
##
|
||||
##
|
||||
##
|
||||
## Copyright (c) 2001, Vipul Ved Prakash. All rights reserved.
|
||||
## This code is free software; you can redistribute it and/or modify
|
||||
## it under the same terms as Perl itself.
|
||||
##
|
||||
## $Id: Armor.pm,v 1.1 2001/03/19 23:15:09 vipul Exp $
|
||||
|
||||
package Convert::ASCII::Armor;
|
||||
use lib "../../../lib";
|
||||
use Convert::ASCII::Armour;
|
||||
use vars qw(@ISA);
|
||||
@ISA = qw(Convert::ASCII::Armour);
|
||||
|
||||
1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Convert::ASCII::Armor - Convert binary octets into ASCII armoured messages.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
See SYNOPSIS in Convert::ASCII::Armour.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Empty subclass of Convert::ASCII::Armour for American English speakers.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Vipul Ved Prakash, E<lt>mail@vipul.netE<gt>
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
247
database/perl/vendor/lib/Convert/ASCII/Armour.pm
vendored
Normal file
247
database/perl/vendor/lib/Convert/ASCII/Armour.pm
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/perl -sw
|
||||
##
|
||||
## Convert::ASCII::Armour
|
||||
##
|
||||
## Copyright (c) 2001, Vipul Ved Prakash. All rights reserved.
|
||||
## This code is free software; you can redistribute it and/or modify
|
||||
## it under the same terms as Perl itself.
|
||||
##
|
||||
## $Id: Armour.pm,v 1.4 2001/03/19 23:15:09 vipul Exp $
|
||||
|
||||
package Convert::ASCII::Armour;
|
||||
use strict;
|
||||
use Digest::MD5 qw(md5);
|
||||
use MIME::Base64;
|
||||
use Compress::Zlib qw(compress uncompress);
|
||||
use vars qw($VERSION);
|
||||
|
||||
($VERSION) = '$Revision: 1.4 $' =~ /\s(\d+\.\d+)\s/;
|
||||
|
||||
|
||||
sub new {
|
||||
return bless {}, shift;
|
||||
}
|
||||
|
||||
|
||||
sub error {
|
||||
my ($self, $errstr) = @_;
|
||||
$$self{errstr} = "$errstr\n";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sub errstr {
|
||||
my $self = shift;
|
||||
return $$self{errstr};
|
||||
}
|
||||
|
||||
|
||||
sub armour {
|
||||
|
||||
my ($self, %params) = @_;
|
||||
|
||||
my $compress = $params{Compress} ? "COMPRESSED " : "";
|
||||
return undef unless $params{Content};
|
||||
$params{Object} = "UNKNOWN $compress DATA" unless $params{Object};
|
||||
|
||||
my $head = "-"x5 . "BEGIN $compress$params{Object}" . "-"x5;
|
||||
my $tail = "-"x5 . "END $compress$params{Object}" . "-"x5;
|
||||
|
||||
my $content = $self->encode_content (%{$params{Content}});
|
||||
$content = compress($content) if $compress;
|
||||
my $checksum = encode_base64 (md5 ($content));
|
||||
my $econtent = encode_base64 ($content);
|
||||
|
||||
my $eheaders = "";
|
||||
for my $key (keys %{$params{Headers}}) {
|
||||
$eheaders .= "$key: $params{Headers}->{$key}\n";
|
||||
}
|
||||
|
||||
my $message = "$head\n$eheaders\n$econtent=$checksum$tail\n";
|
||||
return $message;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub unarmour {
|
||||
my ($self, $message) = @_;
|
||||
|
||||
my ($head, $object, $headers, $content, $tail) = $message =~
|
||||
m:(-----BEGIN ([^\n\-]+)-----)\n(.*?\n\n)?(.+)(-----END .*?-----)$:s
|
||||
or return $self->error ("Breached Armour.");
|
||||
|
||||
my ($compress, $obj) = $object =~ /^(COMPRESSED )(.*)$/;
|
||||
$object = $obj if $obj;
|
||||
$content =~ s:=([^\n]+)$::s or return $self->error ("Breached Armour.");
|
||||
my $checksum = $1; $content = decode_base64 ($content);
|
||||
my $ncheck = encode_base64 (md5 ($content)); $ncheck =~ s/\n//;
|
||||
return $self->error ("Checksum Failed.") unless $ncheck eq $checksum;
|
||||
$content = uncompress ($content) if $compress;
|
||||
my $dcontent = $self->decode_content ($content) || return;
|
||||
|
||||
my $dheaders;
|
||||
if ($headers) {
|
||||
my @pairs = split /\n/, $headers;
|
||||
for (@pairs) {
|
||||
my ($key, $value) = split /: /, $_, 2;
|
||||
$$dheaders{$key} = $value if $key;
|
||||
}
|
||||
}
|
||||
|
||||
my %return = ( Content => $dcontent,
|
||||
Object => $object,
|
||||
Headers => $dheaders );
|
||||
|
||||
return \%return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub encode_content {
|
||||
my ($self, %data) = @_;
|
||||
my $encoded = "";
|
||||
|
||||
for my $key (keys %data) {
|
||||
$encoded .= length ($key) . chr(0) . length ($data{$key}) .
|
||||
chr(0) . "$key$data{$key}";
|
||||
}
|
||||
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
|
||||
sub decode_content {
|
||||
my ($self, $content) = @_;
|
||||
my %data;
|
||||
|
||||
while ($content) {
|
||||
$content =~ s/^(\d+)\x00(\d+)\x00// ||
|
||||
return $self->error ("Inconsistent content.");
|
||||
my $keylen = $1; my $valuelen = $2;
|
||||
my $key = substr $content, 0, $keylen;
|
||||
my $value = substr $content, $keylen, $valuelen;
|
||||
substr ($content, 0, $keylen + $valuelen) = "";
|
||||
$data{$key} = $value;
|
||||
}
|
||||
|
||||
return \%data;
|
||||
}
|
||||
|
||||
|
||||
sub armor { armour (@_) }
|
||||
sub unarmor { unarmour (@_) }
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Convert::ASCII::Armour - Convert binary octets into ASCII armoured messages.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $converter = new Convert::ASCII::Armour;
|
||||
|
||||
my $message = $converter->armour(
|
||||
Object => "FOO RECORD",
|
||||
Headers => {
|
||||
Table => "FooBar",
|
||||
Version => "1.23",
|
||||
},
|
||||
Content => {
|
||||
Key => "0x8738FA7382",
|
||||
Name => "Zoya Hall",
|
||||
Pic => "....", # gif
|
||||
},
|
||||
Compress => 1,
|
||||
);
|
||||
|
||||
print $message;
|
||||
|
||||
|
||||
-----BEGIN COMPRESSED FOO RECORD-----
|
||||
Version: 1.23
|
||||
Table: FooBar
|
||||
|
||||
eJwzZzA0Z/BNLS5OTE8NycgsVgCiRIVciIAJg6EJg0tiSaqhsYJvYlFy...
|
||||
XnpOZl5qYlJySmpaekZmVnZObl5+QWFRcUlpWXlFZRWXAk7g6OTs4urm...
|
||||
Fh4VGaWAR5ehkbGJqZm5hSUeNXWKDsoGcWpaGpq68bba0dWxtTVmDOYM...
|
||||
NzuZ
|
||||
=MxpZvjkrv5XyhkVCuXmsBQ==
|
||||
-----END COMPRESSED FOO RECORD-----
|
||||
|
||||
|
||||
my $decoded = $converter->unarmour( $message )
|
||||
|| die $converter->errstr();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module converts hashes of binary octets into ASCII messages suitable
|
||||
for transfer over 6-bit clean transport channels. The encoded ASCII
|
||||
resembles PGP's armoured messages, but are in no way compatible with PGP.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 B<new()>
|
||||
|
||||
Constructor.
|
||||
|
||||
=head2 B<armour()>
|
||||
|
||||
Converts a hash of binary octets into an ASCII encoded message. The
|
||||
encoded message has 4 parts: head and tail strings that act as identifiers
|
||||
and delimiters, a cluster of headers at top of the message, Base64 encoded
|
||||
message body and a Base64 encoded MD5 digest of the message body. armour()
|
||||
takes a hash as argument with following keys:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<Object>
|
||||
|
||||
An identification string embedded in head and tail strings.
|
||||
|
||||
=item B<Content>
|
||||
|
||||
Content is a hashref that contains the binary octets to be encoded. This
|
||||
hash is serialized, compressed (if specified) and encoded into ASCII with
|
||||
MIME::Base64. The result is the body of the encoded message.
|
||||
|
||||
=item B<Headers>
|
||||
|
||||
Headers is a hashref that contains ASCII headers that are placed at top of
|
||||
the encoded message. Headers are encoded as RFC822 headers.
|
||||
|
||||
=item B<Compress>
|
||||
|
||||
A boolean parameter that forces armour() to compress the message body.
|
||||
|
||||
=back
|
||||
|
||||
=head2 B<unarmour()>
|
||||
|
||||
Decodes an armoured ASCII message into the hash provided as argument
|
||||
to armour(). The hash contains Content, Object, and Headers.
|
||||
unarmour() performs several consistency checks and returns a non-true
|
||||
value on failure.
|
||||
|
||||
=head2 B<errstr()>
|
||||
|
||||
Returns the error message set by unarmour() on failure.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Vipul Ved Prakash, E<lt>mail@vipul.netE<gt>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
Copyright (c) 2001, Vipul Ved Prakash. All rights reserved. This code is
|
||||
free software; you can redistribute it and/or modify it under the same
|
||||
terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
MIME::Base64(3), Compress::Zlib(3), Digest::MD5(3)
|
||||
|
||||
=cut
|
||||
463
database/perl/vendor/lib/Convert/ASN1.pm
vendored
Normal file
463
database/perl/vendor/lib/Convert/ASN1.pm
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
# Copyright (c) 2000-2002 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1;
|
||||
{
|
||||
$Convert::ASN1::VERSION = '0.27';
|
||||
}
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS @opParts @opName $AUTOLOAD);
|
||||
use Exporter;
|
||||
|
||||
use constant CHECK_UTF8 => $] > 5.007;
|
||||
|
||||
BEGIN {
|
||||
local $SIG{__DIE__};
|
||||
eval { require bytes and 'bytes'->import };
|
||||
|
||||
if (CHECK_UTF8) {
|
||||
require Encode;
|
||||
require utf8;
|
||||
}
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
|
||||
%EXPORT_TAGS = (
|
||||
io => [qw(asn_recv asn_send asn_read asn_write asn_get asn_ready)],
|
||||
|
||||
debug => [qw(asn_dump asn_hexdump)],
|
||||
|
||||
const => [qw(ASN_BOOLEAN ASN_INTEGER ASN_BIT_STR ASN_OCTET_STR
|
||||
ASN_NULL ASN_OBJECT_ID ASN_REAL ASN_ENUMERATED
|
||||
ASN_SEQUENCE ASN_SET ASN_PRINT_STR ASN_IA5_STR
|
||||
ASN_UTC_TIME ASN_GENERAL_TIME ASN_RELATIVE_OID
|
||||
ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE
|
||||
ASN_PRIMITIVE ASN_CONSTRUCTOR ASN_LONG_LEN ASN_EXTENSION_ID ASN_BIT)],
|
||||
|
||||
tag => [qw(asn_tag asn_decode_tag2 asn_decode_tag asn_encode_tag asn_decode_length asn_encode_length)]
|
||||
);
|
||||
|
||||
@EXPORT_OK = map { @$_ } values %EXPORT_TAGS;
|
||||
$EXPORT_TAGS{all} = \@EXPORT_OK;
|
||||
|
||||
@opParts = qw(
|
||||
cTAG cTYPE cVAR cLOOP cOPT cEXT cCHILD cDEFINE
|
||||
);
|
||||
|
||||
@opName = qw(
|
||||
opUNKNOWN opBOOLEAN opINTEGER opBITSTR opSTRING opNULL opOBJID opREAL
|
||||
opSEQUENCE opEXPLICIT opSET opUTIME opGTIME opUTF8 opANY opCHOICE opROID opBCD
|
||||
opEXTENSIONS
|
||||
);
|
||||
|
||||
foreach my $l (\@opParts, \@opName) {
|
||||
my $i = 0;
|
||||
foreach my $name (@$l) {
|
||||
my $j = $i++;
|
||||
no strict 'refs';
|
||||
*{__PACKAGE__ . '::' . $name} = sub () { $j }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _internal_syms {
|
||||
my $pkg = caller;
|
||||
no strict 'refs';
|
||||
for my $sub (@opParts,@opName,'dump_op') {
|
||||
*{$pkg . '::' . $sub} = \&{__PACKAGE__ . '::' . $sub};
|
||||
}
|
||||
}
|
||||
|
||||
sub ASN_BOOLEAN () { 0x01 }
|
||||
sub ASN_INTEGER () { 0x02 }
|
||||
sub ASN_BIT_STR () { 0x03 }
|
||||
sub ASN_OCTET_STR () { 0x04 }
|
||||
sub ASN_NULL () { 0x05 }
|
||||
sub ASN_OBJECT_ID () { 0x06 }
|
||||
sub ASN_REAL () { 0x09 }
|
||||
sub ASN_ENUMERATED () { 0x0A }
|
||||
sub ASN_RELATIVE_OID () { 0x0D }
|
||||
sub ASN_SEQUENCE () { 0x10 }
|
||||
sub ASN_SET () { 0x11 }
|
||||
sub ASN_PRINT_STR () { 0x13 }
|
||||
sub ASN_IA5_STR () { 0x16 }
|
||||
sub ASN_UTC_TIME () { 0x17 }
|
||||
sub ASN_GENERAL_TIME () { 0x18 }
|
||||
|
||||
sub ASN_UNIVERSAL () { 0x00 }
|
||||
sub ASN_APPLICATION () { 0x40 }
|
||||
sub ASN_CONTEXT () { 0x80 }
|
||||
sub ASN_PRIVATE () { 0xC0 }
|
||||
|
||||
sub ASN_PRIMITIVE () { 0x00 }
|
||||
sub ASN_CONSTRUCTOR () { 0x20 }
|
||||
|
||||
sub ASN_LONG_LEN () { 0x80 }
|
||||
sub ASN_EXTENSION_ID () { 0x1F }
|
||||
sub ASN_BIT () { 0x80 }
|
||||
|
||||
|
||||
sub new {
|
||||
my $pkg = shift;
|
||||
my $self = bless {}, $pkg;
|
||||
|
||||
$self->configure(@_);
|
||||
$self;
|
||||
}
|
||||
|
||||
|
||||
sub configure {
|
||||
my $self = shift;
|
||||
my %opt = @_;
|
||||
|
||||
$self->{options}{encoding} = uc($opt{encoding} || 'BER');
|
||||
|
||||
unless ($self->{options}{encoding} =~ /^[BD]ER$/) {
|
||||
require Carp;
|
||||
Carp::croak("Unsupported encoding format '$opt{encoding}'");
|
||||
}
|
||||
|
||||
# IMPLICIT as defalt for backwards compatibility, even though it's wrong.
|
||||
$self->{options}{tagdefault} = uc($opt{tagdefault} || 'IMPLICIT');
|
||||
|
||||
unless ($self->{options}{tagdefault} =~ /^(?:EXPLICIT|IMPLICIT)$/) {
|
||||
require Carp;
|
||||
Carp::croak("Default tagging must be EXPLICIT/IMPLICIT. Not $opt{tagdefault}");
|
||||
}
|
||||
|
||||
|
||||
for my $type (qw(encode decode)) {
|
||||
if (exists $opt{$type}) {
|
||||
while(my($what,$value) = each %{$opt{$type}}) {
|
||||
$self->{options}{"${type}_${what}"} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub find {
|
||||
my $self = shift;
|
||||
my $what = shift;
|
||||
return unless exists $self->{tree}{$what};
|
||||
my %new = %$self;
|
||||
$new{script} = $new{tree}->{$what};
|
||||
bless \%new, ref($self);
|
||||
}
|
||||
|
||||
|
||||
sub prepare {
|
||||
my $self = shift;
|
||||
my $asn = shift;
|
||||
|
||||
$self = $self->new unless ref($self);
|
||||
my $tree;
|
||||
if( ref($asn) eq 'GLOB' ){
|
||||
local $/ = undef;
|
||||
my $txt = <$asn>;
|
||||
$tree = Convert::ASN1::parser::parse($txt,$self->{options}{tagdefault});
|
||||
} else {
|
||||
$tree = Convert::ASN1::parser::parse($asn,$self->{options}{tagdefault});
|
||||
}
|
||||
|
||||
unless ($tree) {
|
||||
$self->{error} = $@;
|
||||
return;
|
||||
### If $self has been set to a new object, not returning
|
||||
### this object here will destroy the object, so the caller
|
||||
### won't be able to get at the error.
|
||||
}
|
||||
|
||||
$self->{tree} = _pack_struct($tree);
|
||||
$self->{script} = (values %$tree)[0];
|
||||
$self;
|
||||
}
|
||||
|
||||
sub prepare_file {
|
||||
my $self = shift;
|
||||
my $asnp = shift;
|
||||
|
||||
local *ASN;
|
||||
open( ASN, $asnp )
|
||||
or do{ $self->{error} = $@; return; };
|
||||
my $ret = $self->prepare( \*ASN );
|
||||
close( ASN );
|
||||
$ret;
|
||||
}
|
||||
|
||||
sub registeroid {
|
||||
my $self = shift;
|
||||
my $oid = shift;
|
||||
my $handler = shift;
|
||||
|
||||
$self->{options}{oidtable}{$oid}=$handler;
|
||||
$self->{oidtable}{$oid}=$handler;
|
||||
}
|
||||
|
||||
sub registertype {
|
||||
my $self = shift;
|
||||
my $def = shift;
|
||||
my $type = shift;
|
||||
my $handler = shift;
|
||||
|
||||
$self->{options}{handlers}{$def}{$type}=$handler;
|
||||
}
|
||||
|
||||
# In XS the will convert the tree between perl and C structs
|
||||
|
||||
sub _pack_struct { $_[0] }
|
||||
sub _unpack_struct { $_[0] }
|
||||
|
||||
##
|
||||
## Encoding
|
||||
##
|
||||
|
||||
sub encode {
|
||||
my $self = shift;
|
||||
my $stash = @_ == 1 ? shift : { @_ };
|
||||
my $buf = '';
|
||||
local $SIG{__DIE__};
|
||||
eval { _encode($self->{options}, $self->{script}, $stash, [], $buf) }
|
||||
or do { $self->{error} = $@; undef }
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Encode tag value for encoding.
|
||||
# We assume that the tag has been correctly generated with asn_tag()
|
||||
|
||||
sub asn_encode_tag {
|
||||
$_[0] >> 8
|
||||
? $_[0] & 0x8000
|
||||
? $_[0] & 0x800000
|
||||
? pack("V",$_[0])
|
||||
: substr(pack("V",$_[0]),0,3)
|
||||
: pack("v", $_[0])
|
||||
: pack("C",$_[0]);
|
||||
}
|
||||
|
||||
|
||||
# Encode a length. If < 0x80 then encode as a byte. Otherwise encode
|
||||
# 0x80 | num_bytes followed by the bytes for the number. top end
|
||||
# bytes of all zeros are not encoded
|
||||
|
||||
sub asn_encode_length {
|
||||
|
||||
if($_[0] >> 7) {
|
||||
my $lenlen = &num_length;
|
||||
|
||||
return pack("Ca*", $lenlen | 0x80, substr(pack("N",$_[0]), -$lenlen));
|
||||
}
|
||||
|
||||
return pack("C", $_[0]);
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
## Decoding
|
||||
##
|
||||
|
||||
sub decode {
|
||||
my $self = shift;
|
||||
my $ret;
|
||||
|
||||
local $SIG{__DIE__};
|
||||
eval {
|
||||
my (%stash, $result);
|
||||
my $script = $self->{script};
|
||||
my $stash = \$result;
|
||||
|
||||
while ($script) {
|
||||
my $child = $script->[0] or last;
|
||||
if (@$script > 1 or defined $child->[cVAR]) {
|
||||
$result = $stash = \%stash;
|
||||
last;
|
||||
}
|
||||
last if $child->[cTYPE] == opCHOICE or $child->[cLOOP];
|
||||
$script = $child->[cCHILD];
|
||||
}
|
||||
|
||||
_decode(
|
||||
$self->{options},
|
||||
$self->{script},
|
||||
$stash,
|
||||
0,
|
||||
length $_[0],
|
||||
undef,
|
||||
{},
|
||||
$_[0]);
|
||||
|
||||
$ret = $result;
|
||||
1;
|
||||
} or $self->{'error'} = $@ || 'Unknown error';
|
||||
|
||||
$ret;
|
||||
}
|
||||
|
||||
|
||||
sub asn_decode_length {
|
||||
return unless length $_[0];
|
||||
|
||||
my $len = unpack("C",$_[0]);
|
||||
|
||||
if($len & 0x80) {
|
||||
$len &= 0x7f or return (1,-1);
|
||||
|
||||
return if $len >= length $_[0];
|
||||
|
||||
return (1+$len, unpack("N", "\0" x (4 - $len) . substr($_[0],1,$len)));
|
||||
}
|
||||
return (1, $len);
|
||||
}
|
||||
|
||||
|
||||
sub asn_decode_tag {
|
||||
return unless length $_[0];
|
||||
|
||||
my $tag = unpack("C", $_[0]);
|
||||
my $n = 1;
|
||||
|
||||
if(($tag & 0x1f) == 0x1f) {
|
||||
my $b;
|
||||
do {
|
||||
return if $n >= length $_[0];
|
||||
$b = unpack("C",substr($_[0],$n,1));
|
||||
$tag |= $b << (8 * $n++);
|
||||
} while($b & 0x80);
|
||||
}
|
||||
($n, $tag);
|
||||
}
|
||||
|
||||
|
||||
sub asn_decode_tag2 {
|
||||
return unless length $_[0];
|
||||
|
||||
my $tag = unpack("C",$_[0]);
|
||||
my $num = $tag & 0x1f;
|
||||
my $len = 1;
|
||||
|
||||
if($num == 0x1f) {
|
||||
$num = 0;
|
||||
my $b;
|
||||
do {
|
||||
return if $len >= length $_[0];
|
||||
$b = unpack("C",substr($_[0],$len++,1));
|
||||
$num = ($num << 7) + ($b & 0x7f);
|
||||
} while($b & 0x80);
|
||||
}
|
||||
($len, $tag, $num);
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
## Utilities
|
||||
##
|
||||
|
||||
# How many bytes are needed to encode a number
|
||||
|
||||
sub num_length {
|
||||
$_[0] >> 8
|
||||
? $_[0] >> 16
|
||||
? $_[0] >> 24
|
||||
? 4
|
||||
: 3
|
||||
: 2
|
||||
: 1
|
||||
}
|
||||
|
||||
# Convert from a bigint to an octet string
|
||||
|
||||
sub i2osp {
|
||||
my($num, $biclass) = @_;
|
||||
eval "use $biclass";
|
||||
$num = $biclass->new($num);
|
||||
my $neg = $num < 0
|
||||
and $num = abs($num+1);
|
||||
my $base = $biclass->new(256);
|
||||
my $result = '';
|
||||
while($num != 0) {
|
||||
my $r = $num % $base;
|
||||
$num = ($num-$r) / $base;
|
||||
$result .= pack("C",$r);
|
||||
}
|
||||
$result ^= pack("C",255) x length($result) if $neg;
|
||||
return scalar reverse $result;
|
||||
}
|
||||
|
||||
# Convert from an octet string to a bigint
|
||||
|
||||
sub os2ip {
|
||||
my($os, $biclass) = @_;
|
||||
eval "require $biclass";
|
||||
my $base = $biclass->new(256);
|
||||
my $result = $biclass->new(0);
|
||||
my $neg = unpack("C",$os) >= 0x80
|
||||
and $os ^= pack("C",255) x length($os);
|
||||
for (unpack("C*",$os)) {
|
||||
$result = ($result * $base) + $_;
|
||||
}
|
||||
return $neg ? ($result + 1) * -1 : $result;
|
||||
}
|
||||
|
||||
# Given a class and a tag, calculate an integer which when encoded
|
||||
# will become the tag. This means that the class bits are always
|
||||
# in the bottom byte, so are the tag bits if tag < 30. Otherwise
|
||||
# the tag is in the upper 3 bytes. The upper bytes are encoded
|
||||
# with bit8 representing that there is another byte. This
|
||||
# means the max tag we can do is 0x1fffff
|
||||
|
||||
sub asn_tag {
|
||||
my($class,$value) = @_;
|
||||
|
||||
die sprintf "Bad tag class 0x%x",$class
|
||||
if $class & ~0xe0;
|
||||
|
||||
unless ($value & ~0x1f or $value == 0x1f) {
|
||||
return (($class & 0xe0) | $value);
|
||||
}
|
||||
|
||||
die sprintf "Tag value 0x%08x too big\n",$value
|
||||
if $value & 0xffe00000;
|
||||
|
||||
$class = ($class | 0x1f) & 0xff;
|
||||
|
||||
my @t = ($value & 0x7f);
|
||||
unshift @t, (0x80 | ($value & 0x7f)) while $value >>= 7;
|
||||
unpack("V",pack("C4",$class,@t,0,0));
|
||||
}
|
||||
|
||||
|
||||
BEGIN {
|
||||
# When we have XS &_encode will be defined by the XS code
|
||||
# so will all the subs in these required packages
|
||||
unless (defined &_encode) {
|
||||
require Convert::ASN1::_decode;
|
||||
require Convert::ASN1::_encode;
|
||||
require Convert::ASN1::IO;
|
||||
}
|
||||
|
||||
require Convert::ASN1::parser;
|
||||
}
|
||||
|
||||
sub AUTOLOAD {
|
||||
require Convert::ASN1::Debug if $AUTOLOAD =~ /dump/;
|
||||
goto &{$AUTOLOAD} if defined &{$AUTOLOAD};
|
||||
require Carp;
|
||||
my $pkg = ref($_[0]) || ($_[0] =~ /^[\w\d]+(?:::[\w\d]+)*$/)[0];
|
||||
if ($pkg and UNIVERSAL::isa($pkg, __PACKAGE__)) { # guess it was a method call
|
||||
$AUTOLOAD =~ s/.*:://;
|
||||
Carp::croak(sprintf q{Can't locate object method "%s" via package "%s"},$AUTOLOAD,$pkg);
|
||||
}
|
||||
else {
|
||||
Carp::croak(sprintf q{Undefined subroutine &%s called}, $AUTOLOAD);
|
||||
}
|
||||
}
|
||||
|
||||
sub DESTROY {}
|
||||
|
||||
sub error { $_[0]->{error} }
|
||||
1;
|
||||
514
database/perl/vendor/lib/Convert/ASN1.pod
vendored
Normal file
514
database/perl/vendor/lib/Convert/ASN1.pod
vendored
Normal file
@@ -0,0 +1,514 @@
|
||||
=head1 NAME
|
||||
|
||||
Convert::ASN1 - ASN.1 Encode/Decode library
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 0.27
|
||||
|
||||
=head1 SYNOPSYS
|
||||
|
||||
use Convert::ASN1;
|
||||
|
||||
$asn = Convert::ASN1->new;
|
||||
$asn->prepare(q<
|
||||
|
||||
[APPLICATION 7] SEQUENCE {
|
||||
int INTEGER,
|
||||
str OCTET STRING
|
||||
}
|
||||
|
||||
>);
|
||||
|
||||
$pdu = $asn->encode( int => 7, str => "string");
|
||||
|
||||
$out = $asn->decode($pdu);
|
||||
print $out->{int}," ",$out->{str},"\n";
|
||||
|
||||
use Convert::ASN1 qw(:io);
|
||||
|
||||
$peer = asn_recv($sock,$buffer,0);
|
||||
$nbytes = asn_read($fh, $buffer);
|
||||
$nbytes = asn_send($sock, $buffer, $peer);
|
||||
$nbytes = asn_send($sock, $buffer);
|
||||
$nbytes = asn_write($fh, $buffer);
|
||||
$buffer = asn_get($fh);
|
||||
$yes = asn_ready($fh)
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Convert::ASN1 encodes and decodes ASN.1 data structures using BER/DER
|
||||
rules.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new ( [OPTIONS] )
|
||||
|
||||
Contructor, creates a new object.
|
||||
|
||||
If given, B<OPTIONS> are the same ones as for L</"configure ( OPTIONS )"> below.
|
||||
|
||||
=head2 error ()
|
||||
|
||||
Returns the last error.
|
||||
|
||||
=head2 configure ( OPTIONS )
|
||||
|
||||
Configure options to control how Convert::ASN1 will perform various tasks.
|
||||
Options are passed as name-value pairs.
|
||||
|
||||
=over 4
|
||||
|
||||
=item encode
|
||||
|
||||
Reference to a hash which contains various encode options.
|
||||
|
||||
=item decode
|
||||
|
||||
Reference to a hash which contains various decode options.
|
||||
|
||||
=item encoding
|
||||
|
||||
One of 'BER' or 'DER'. The default is 'BER'
|
||||
|
||||
=item tagdefault
|
||||
|
||||
One of 'EXPLICIT' or 'IMPLICIT'.
|
||||
Default tagging conventions are normally given in the ASN.1 module definition (not supported by the parser). The ASN.1 spec states EXPLICIT tagging is the default, but this option has IMPLICIT tagging default for backward compatibility reasons.
|
||||
|
||||
=back
|
||||
|
||||
Encode options
|
||||
|
||||
=over 4
|
||||
|
||||
=item real
|
||||
|
||||
Which encoding to use for real's. One of 'binary', 'nr1', 'nr2', 'nr3'
|
||||
|
||||
=item time
|
||||
|
||||
This controls how UTCTime and GeneralizedTime elements are encoded. The default
|
||||
is C<withzone>.
|
||||
|
||||
=over 4
|
||||
|
||||
=item utctime
|
||||
|
||||
The value passed will be encoded without a zone, ie a UTC value.
|
||||
|
||||
=item withzone
|
||||
|
||||
The value will be encoded with a zone. By default it will be encoded
|
||||
using the local time offset. The offset may be set using the C<timezone>
|
||||
configure option.
|
||||
|
||||
=item raw
|
||||
|
||||
The value passed should already be in the correct format and will be copied
|
||||
into the PDU as-is.
|
||||
|
||||
=back
|
||||
|
||||
=item timezone
|
||||
|
||||
By default UTCTime and GeneralizedTime will be encoded using the local
|
||||
time offset from UTC. This will over-ride that. It is an offset from UTC
|
||||
in seconds. This option can be overridden by passing a reference to a
|
||||
list of two values as the time value. The list should contain the time
|
||||
value and the offset from UTC in seconds.
|
||||
|
||||
=item bigint
|
||||
|
||||
If during encoding an value greater than 32 bits is discovered and
|
||||
is not already a big integer object, then the value will first be
|
||||
converted into a big integer object. This option controls the big
|
||||
integer class into which the objects will be blessed. The default
|
||||
is to use Math::BigInt
|
||||
|
||||
=back
|
||||
|
||||
Decode options
|
||||
|
||||
=over 4
|
||||
|
||||
=item time
|
||||
|
||||
This controls how a UTCTime or a GeneralizedTime element will be decoded. The default
|
||||
is C<utctime>.
|
||||
|
||||
=over 4
|
||||
|
||||
=item utctime
|
||||
|
||||
The value returned will be a time value as returned by the C<time> function.
|
||||
|
||||
=item withzone
|
||||
|
||||
The value returned will be a reference to an array of two values. The first is the
|
||||
same as with C<utctime>, the second is the timezone offset, in seconds, that was
|
||||
used in the encoding.
|
||||
|
||||
=item raw
|
||||
|
||||
The value returned will be the raw encoding as extracted from the PDU.
|
||||
|
||||
=back
|
||||
|
||||
=item bigint
|
||||
|
||||
If during decoding any big integers are discovered (integers greater
|
||||
than 32 bits), they will be decoded into big integer objects. This option
|
||||
controls the big integer class into which the objects will be blessed.
|
||||
The default is to use Math::BigInt.
|
||||
|
||||
=item null
|
||||
|
||||
The value to decode ASN.1 NULL types into.
|
||||
If not set, it defaults to C<1>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 prepare ( ASN )
|
||||
|
||||
Compile the given ASN.1 descripton which can be passed as a string
|
||||
or as a filehandle. The syntax used is very close to ASN.1, but has
|
||||
a few differences. If the ASN decribes only one macro then encode/decode can be
|
||||
called on this object. If ASN describes more than one ASN.1 macro then C<find>
|
||||
must be called. The method returns undef on error.
|
||||
|
||||
=head2 prepare_file ( ASNPATH )
|
||||
|
||||
Compile the ASN.1 description to be read from the specified pathname.
|
||||
|
||||
=head2 find ( MACRO )
|
||||
|
||||
Find a macro from a prepared ASN.1 description. Returns an object which can
|
||||
be used for encode/decode.
|
||||
|
||||
=head2 encode ( VARIABLES )
|
||||
|
||||
Encode a PDU. Top-level variable are passed as name-value pairs, or as a reference
|
||||
to a hash containing them. Returns the encoded PDU, or undef on error.
|
||||
|
||||
=head2 decode ( PDU )
|
||||
|
||||
Decode the PDU, returns a reference to a hash containg the values for the PDU. Returns
|
||||
undef if there was an error.
|
||||
|
||||
=head2 registeroid ( OID, HANDLER )
|
||||
|
||||
Register a handler for all ASN.1 elements
|
||||
that are C<DEFINED BY> the given OID.
|
||||
|
||||
B<HANDLER> must be a Convert::ASN1 object, e.g. as returned by L</"find ( MACRO )">.
|
||||
|
||||
=head2 registertype ( NAME, OID, HANDLER )
|
||||
|
||||
Register a handler for all ASN.1 elements named C<NAME>,
|
||||
that are C<DEFINED BY> the given OID.
|
||||
|
||||
B<HANDLER> must be a Convert::ASN1 object, e.g. as returned by L</"find ( MACRO )">.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
As well as providing an object interface for encoding/decoding PDUs Convert::ASN1
|
||||
also provides the following functions.
|
||||
|
||||
=head2 IO Functions
|
||||
|
||||
=over 4
|
||||
|
||||
=item asn_recv ( SOCK, BUFFER, FLAGS )
|
||||
|
||||
Will read a single element from the socket SOCK into BUFFER. FLAGS may
|
||||
be MSG_PEEK as exported by C<Socket>. Returns the address of the sender,
|
||||
or undef if there was an error. Some systems do not support the return
|
||||
of the peer address when the socket is a connected socket, in these
|
||||
cases the empty string will be returned. This is the same behaviour
|
||||
as the C<recv> function in perl itself.
|
||||
|
||||
It is recommended that if the socket is of type SOCK_DGRAM then C<recv>
|
||||
be called directly instead of calling C<asn_recv>.
|
||||
|
||||
=item asn_read ( FH, BUFFER, OFFSET )
|
||||
|
||||
=item asn_read ( FH, BUFFER )
|
||||
|
||||
Will read a single element from the filehandle FH into BUFFER. Returns the
|
||||
number of bytes read if a complete element was read, -1 if an incomplete
|
||||
element was read or undef if there was an error. If OFFSET is specified
|
||||
then it is assumed that BUFFER already contains an incomplete element
|
||||
and new data will be appended starting at OFFSET.
|
||||
|
||||
If FH is a socket the asn_recv is used to read the element, so the same
|
||||
restiction applies if FH is a socket of type SOCK_DGRAM.
|
||||
|
||||
=item asn_send ( SOCK, BUFFER, FLAGS, TO )
|
||||
|
||||
=item asn_send ( SOCK, BUFFER, FLAGS )
|
||||
|
||||
Identical to calling C<send>, see L<perlfunc>
|
||||
|
||||
=item asn_write ( FH, BUFFER )
|
||||
|
||||
Identical to calling C<syswrite> with 2 arguments, see L<perlfunc>
|
||||
|
||||
=item asn_get ( FH )
|
||||
|
||||
C<asn_get> provides buffered IO. Because it needs a buffer FH must be a GLOB
|
||||
or a reference to a GLOB. C<asn_get> will use two entries in the hash element
|
||||
of the GLOB to use as its buffer:
|
||||
|
||||
asn_buffer - input buffer
|
||||
asn_need - number of bytes needed for the next element, if known
|
||||
|
||||
Returns an element or undef if there was an error.
|
||||
|
||||
=item asn_ready ( FH )
|
||||
|
||||
C<asn_ready> works with C<asn_get>. It will return true if C<asn_get> has already
|
||||
read enough data into the buffer to return a complete element.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Encode/Decode Functions
|
||||
|
||||
=over 4
|
||||
|
||||
=item asn_tag ( CLASS, VALUE )
|
||||
|
||||
Given B<CLASS> and a B<VALUE>, calculate an integer which when encoded
|
||||
will become the tag.
|
||||
|
||||
=item asn_decode_tag ( TAG )
|
||||
|
||||
Decode the given ASN.1 encoded C<TAG>.
|
||||
|
||||
=item asn_encode_tag ( TAG )
|
||||
|
||||
Encode B<TAG> value for encoding.
|
||||
We assume that the tag has been correctly generated with L</"asn_tag ( CLASS, VALUE )">.
|
||||
|
||||
=item asn_decode_length ( LEN )
|
||||
|
||||
Decode the given ASN.1 decoded C<LEN>.
|
||||
|
||||
=item asn_encode_length ( LEN )
|
||||
|
||||
Encode the given C<LEN> to its ASN.1 encoding.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Constants
|
||||
|
||||
=over 4
|
||||
|
||||
=item ASN_BIT_STR
|
||||
|
||||
=item ASN_BOOLEAN
|
||||
|
||||
=item ASN_ENUMERATED
|
||||
|
||||
=item ASN_GENERAL_TIME
|
||||
|
||||
=item ASN_IA5_STR
|
||||
|
||||
=item ASN_INTEGER
|
||||
|
||||
=item ASN_NULL
|
||||
|
||||
=item ASN_OBJECT_ID
|
||||
|
||||
=item ASN_OCTET_STR
|
||||
|
||||
=item ASN_PRINT_STR
|
||||
|
||||
=item ASN_REAL
|
||||
|
||||
=item ASN_SEQUENCE
|
||||
|
||||
=item ASN_SET
|
||||
|
||||
=item ASN_UTC_TIME
|
||||
|
||||
=item ASN_APPLICATION
|
||||
|
||||
=item ASN_CONTEXT
|
||||
|
||||
=item ASN_PRIVATE
|
||||
|
||||
=item ASN_UNIVERSAL
|
||||
|
||||
=item ASN_PRIMITIVE
|
||||
|
||||
=item ASN_CONSTRUCTOR
|
||||
|
||||
=item ASN_LONG_LEN
|
||||
|
||||
=item ASN_EXTENSION_ID
|
||||
|
||||
=item ASN_BIT
|
||||
|
||||
=back
|
||||
|
||||
=head2 Debug Functions
|
||||
|
||||
=over 4
|
||||
|
||||
=item asn_dump ( [FH,] BUFFER )
|
||||
|
||||
Try to decode the given buffer as ASN.1 structure and dump it to the
|
||||
given file handle, or C<STDERR> if the handle is not given.
|
||||
|
||||
=item asn_hexdump ( FH, BUFFER )
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXPORT TAGS
|
||||
|
||||
=over 4
|
||||
|
||||
=item :all
|
||||
|
||||
All exported functions
|
||||
|
||||
=item :const
|
||||
|
||||
ASN_BOOLEAN, ASN_INTEGER, ASN_BIT_STR, ASN_OCTET_STR,
|
||||
ASN_NULL, ASN_OBJECT_ID, ASN_REAL, ASN_ENUMERATED,
|
||||
ASN_SEQUENCE, ASN_SET, ASN_PRINT_STR, ASN_IA5_STR,
|
||||
ASN_UTC_TIME, ASN_GENERAL_TIME,
|
||||
ASN_UNIVERSAL, ASN_APPLICATION, ASN_CONTEXT, ASN_PRIVATE,
|
||||
ASN_PRIMITIVE, ASN_CONSTRUCTOR, ASN_LONG_LEN, ASN_EXTENSION_ID, ASN_BIT
|
||||
|
||||
=item :debug
|
||||
|
||||
asn_dump, asn_hexdump
|
||||
|
||||
=item :io
|
||||
|
||||
asn_recv, asn_send, asn_read, asn_write, asn_get, asn_ready
|
||||
|
||||
=item :tag
|
||||
|
||||
asn_tag, asn_decode_tag, asn_encode_tag, asn_decode_length, asn_encode_length
|
||||
|
||||
=back
|
||||
|
||||
=head1 MAPPING ASN.1 TO PERL
|
||||
|
||||
Every element in the ASN.1 definition has a name, in perl a hash is used
|
||||
with these names as an index and the element value as the hash value.
|
||||
|
||||
# ASN.1
|
||||
int INTEGER,
|
||||
str OCTET STRING
|
||||
|
||||
# Perl
|
||||
{ int => 5, str => "text" }
|
||||
|
||||
|
||||
In the case of a SEQUENCE, SET or CHOICE then the value in the namespace will
|
||||
be a hash reference which will be the namespce for the elements with
|
||||
that element.
|
||||
|
||||
# ASN.1
|
||||
int INTEGER,
|
||||
seq SEQUENCE {
|
||||
str OCTET STRING,
|
||||
bool BOOLEAN
|
||||
}
|
||||
|
||||
# Perl
|
||||
{ int => 5, seq => { str => "text", bool => 1}}
|
||||
|
||||
If the element is a SEQUENCE OF, or SET OF, then the value in the namespace
|
||||
will be an array reference. The elements in the array will be of
|
||||
the type expected by the type following the OF. For example
|
||||
with "SEQUENCE OF STRING" the array would contain strings. With
|
||||
"SEQUENCE OF SEQUENCE { ... }" the array will contain hash references
|
||||
which will be used as namespaces
|
||||
|
||||
# ASN.1
|
||||
int INTEGER,
|
||||
str SEQUENCE OF OCTET STRING
|
||||
|
||||
# Perl
|
||||
{ int => 5, str => [ "text1", "text2"]}
|
||||
|
||||
# ASN.1
|
||||
int INTEGER,
|
||||
str SEQUENCE OF SEQUENCE {
|
||||
type OCTET STRING,
|
||||
value INTEGER
|
||||
}
|
||||
|
||||
# Perl
|
||||
{ int => 5, str => [
|
||||
{ type => "abc", value => 4 },
|
||||
{ type => "def", value => -1 },
|
||||
]}
|
||||
|
||||
Finally, if you wish to pre-parse ASN.1 and hold it to include
|
||||
inline in your PDU, you can coerce it into the ASN.1 spec by
|
||||
defining the value as ANY in the schema, and then pass the pre
|
||||
encoded value inline.
|
||||
|
||||
# ASN.1
|
||||
int INTEGER,
|
||||
str OCTET STRING,
|
||||
pre ANY
|
||||
|
||||
# Perl
|
||||
{ int => 5, str => "text", pre=>"\x03\x03\x00\x0a\x05" }
|
||||
|
||||
passes a pre-encoded BIT STRING instance as hex text. -But
|
||||
it could be a previous run of $obj->encode() from another run
|
||||
held in some variable.
|
||||
|
||||
|
||||
=head2 Exceptions
|
||||
|
||||
There are some exceptions where Convert::ASN1 does not require an element to be named.
|
||||
These are SEQUENCE {...}, SET {...} and CHOICE. In each case if the element is not
|
||||
given a name then the elements inside the {...} will share the same namespace as
|
||||
the elements outside of the {...}.
|
||||
|
||||
=head1 TODO
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
XS implementation.
|
||||
|
||||
=item *
|
||||
|
||||
More documentation.
|
||||
|
||||
=item *
|
||||
|
||||
More tests.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Graham Barr <gbarr@cpan.org>
|
||||
|
||||
=head1 SUPPORT
|
||||
|
||||
Report issues via github at https://github.com/gbarr/perl-Convert-ASN1/issues
|
||||
|
||||
To contribute I encourage you to create a git fork of the repository at
|
||||
https://github.com/gbarr/perl-Convert-ASN1 do you work on a fresh branch
|
||||
created from master and submit a pull request
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2000-2012 Graham Barr <gbarr@cpan.org>. All rights reserved.
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
231
database/perl/vendor/lib/Convert/ASN1/Debug.pm
vendored
Normal file
231
database/perl/vendor/lib/Convert/ASN1/Debug.pm
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1;
|
||||
{
|
||||
$Convert::ASN1::VERSION = '0.27';
|
||||
}
|
||||
|
||||
##
|
||||
## just for debug :-)
|
||||
##
|
||||
|
||||
sub _hexdump {
|
||||
my($fmt,$pos) = @_[1,2]; # Don't copy buffer
|
||||
|
||||
$pos ||= 0;
|
||||
|
||||
my $offset = 0;
|
||||
my $cnt = 1 << 4;
|
||||
my $len = length($_[0]);
|
||||
my $linefmt = ("%02X " x $cnt) . "%s\n";
|
||||
|
||||
print "\n";
|
||||
|
||||
while ($offset < $len) {
|
||||
my $data = substr($_[0],$offset,$cnt);
|
||||
my @y = unpack("C*",$data);
|
||||
|
||||
printf $fmt,$pos if $fmt;
|
||||
|
||||
# On the last time through replace '%02X ' with '__ ' for the
|
||||
# missing values
|
||||
substr($linefmt, 5*@y,5*($cnt-@y)) = "__ " x ($cnt - @y)
|
||||
if @y != $cnt;
|
||||
|
||||
# Change non-printable chars to '.'
|
||||
$data =~ s/[\x00-\x1f\x7f-\xff]/./sg;
|
||||
printf $linefmt, @y,$data;
|
||||
|
||||
$offset += $cnt;
|
||||
$pos += $cnt;
|
||||
}
|
||||
}
|
||||
|
||||
my %type = (
|
||||
split(/[\t\n]\s*/,
|
||||
q(10 SEQUENCE
|
||||
01 BOOLEAN
|
||||
0A ENUM
|
||||
0D RELATIVE-OID
|
||||
11 SET
|
||||
02 INTEGER
|
||||
03 BIT STRING
|
||||
C0 [PRIVATE %d]
|
||||
04 STRING
|
||||
40 [APPLICATION %d]
|
||||
05 NULL
|
||||
06 OBJECT ID
|
||||
80 [CONTEXT %d]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
BEGIN { undef &asn_dump }
|
||||
sub asn_dump {
|
||||
my $fh = @_>1 ? shift : \*STDERR;
|
||||
|
||||
my $ofh = select($fh);
|
||||
|
||||
my $pos = 0;
|
||||
my $indent = "";
|
||||
my @seqend = ();
|
||||
my $length = length($_[0]);
|
||||
my $fmt = $length > 0xffff ? "%08X" : "%04X";
|
||||
|
||||
while(1) {
|
||||
while (@seqend && $pos >= $seqend[0]) {
|
||||
$indent = substr($indent,2);
|
||||
warn "Bad sequence length " unless $pos == shift @seqend;
|
||||
printf "$fmt : %s}\n",$pos,$indent;
|
||||
}
|
||||
last unless $pos < $length;
|
||||
|
||||
my $start = $pos;
|
||||
my($tb,$tag,$tnum) = asn_decode_tag2(substr($_[0],$pos,10));
|
||||
last unless defined $tb;
|
||||
$pos += $tb;
|
||||
my($lb,$len) = asn_decode_length(substr($_[0],$pos,10));
|
||||
$pos += $lb;
|
||||
|
||||
if($tag == 0 && $len == 0) {
|
||||
$seqend[0] = $pos;
|
||||
redo;
|
||||
}
|
||||
printf $fmt. " %4d: %s",$start,$len,$indent;
|
||||
|
||||
my $label = $type{sprintf("%02X",$tag & ~0x20)}
|
||||
|| $type{sprintf("%02X",$tag & 0xC0)}
|
||||
|| "[UNIVERSAL %d]";
|
||||
printf $label, $tnum;
|
||||
|
||||
if ($tag & ASN_CONSTRUCTOR) {
|
||||
print " {\n";
|
||||
if($len < 0) {
|
||||
unshift(@seqend, length $_[0]);
|
||||
}
|
||||
else {
|
||||
unshift(@seqend, $pos + $len);
|
||||
}
|
||||
$indent .= " ";
|
||||
next;
|
||||
}
|
||||
|
||||
my $tmp;
|
||||
|
||||
for ($label) { # switch
|
||||
/^(INTEGER|ENUM)/ && do {
|
||||
Convert::ASN1::_dec_integer({},[],{},$tmp,$_[0],$pos,$len);
|
||||
printf " = %d\n",$tmp;
|
||||
last;
|
||||
};
|
||||
|
||||
/^BOOLEAN/ && do {
|
||||
Convert::ASN1::_dec_boolean({},[],{},$tmp,$_[0],$pos,$len);
|
||||
printf " = %s\n",$tmp ? 'TRUE' : 'FALSE';
|
||||
last;
|
||||
};
|
||||
|
||||
/^(?:(OBJECT ID)|(RELATIVE-OID))/ && do {
|
||||
my @op; $op[cTYPE] = $1 ? opOBJID : opROID;
|
||||
Convert::ASN1::_dec_object_id({},\@op,{},$tmp,$_[0],$pos,$len);
|
||||
printf " = %s\n",$tmp;
|
||||
last;
|
||||
};
|
||||
|
||||
/^NULL/ && do {
|
||||
print "\n";
|
||||
last;
|
||||
};
|
||||
|
||||
/^STRING/ && do {
|
||||
Convert::ASN1::_dec_string({},[],{},$tmp,$_[0],$pos,$len);
|
||||
if ($tmp =~ /[\x00-\x1f\x7f-\xff]/s) {
|
||||
_hexdump($tmp,$fmt . " : ".$indent, $pos);
|
||||
}
|
||||
else {
|
||||
printf " = '%s'\n",$tmp;
|
||||
}
|
||||
last;
|
||||
};
|
||||
|
||||
# /^BIT STRING/ && do {
|
||||
# Convert::BER::BIT_STRING->unpack($ber,\$tmp);
|
||||
# print " = ",$tmp,"\n";
|
||||
# last;
|
||||
# };
|
||||
|
||||
# default -- dump hex data
|
||||
_hexdump(substr($_[0],$pos,$len),$fmt . " : ".$indent, $pos);
|
||||
}
|
||||
$pos += $len;
|
||||
}
|
||||
printf "Buffer contains %d extra bytes\n", $length - $pos if $pos < $length;
|
||||
|
||||
select($ofh);
|
||||
}
|
||||
|
||||
BEGIN { undef &asn_hexdump }
|
||||
sub asn_hexdump {
|
||||
my $fh = @_>1 ? shift : \*STDERR;
|
||||
my $ofh = select($fh);
|
||||
|
||||
_hexdump($_[0]);
|
||||
print "\n";
|
||||
select($ofh);
|
||||
}
|
||||
|
||||
BEGIN { undef &dump }
|
||||
sub dump {
|
||||
my $self = shift;
|
||||
|
||||
for (@{$self->{script}}) {
|
||||
dump_op($_,"",{},1);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN { undef &dump_all }
|
||||
sub dump_all {
|
||||
my $self = shift;
|
||||
|
||||
while(my($k,$v) = each %{$self->{tree}}) {
|
||||
print STDERR "$k:\n";
|
||||
for (@$v) {
|
||||
dump_op($_,"",{},1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BEGIN { undef &dump_op }
|
||||
sub dump_op {
|
||||
my($op,$indent,$done,$line) = @_;
|
||||
$indent ||= "";
|
||||
printf STDERR "%3d: ",$line;
|
||||
if ($done->{$op}) {
|
||||
print STDERR " $indent=",$done->{$op},"\n";
|
||||
return ++$line;
|
||||
}
|
||||
$done->{$op} = $line++;
|
||||
print STDERR $indent,"[ '",unpack("H*",$op->[cTAG]),"', ";
|
||||
print STDERR $op->[cTYPE] =~ /\D/ ? $op->[cTYPE] : $opName[$op->[cTYPE]];
|
||||
print STDERR ", ",defined($op->[cVAR]) ? $op->[cVAR] : "_";
|
||||
print STDERR ", ",defined($op->[cLOOP]) ? $op->[cLOOP] : "_";
|
||||
print STDERR ", ",defined($op->[cOPT]) ? $op->[cOPT] : "_";
|
||||
print STDERR "]";
|
||||
if ($op->[cCHILD]) {
|
||||
print STDERR " ",scalar @{$op->[cCHILD]},"\n";
|
||||
for (@{$op->[cCHILD]}) {
|
||||
$line = dump_op($_,$indent . " ",$done,$line);
|
||||
}
|
||||
}
|
||||
else {
|
||||
print STDERR "\n";
|
||||
}
|
||||
print STDERR "\n" unless length $indent;
|
||||
$line;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
264
database/perl/vendor/lib/Convert/ASN1/IO.pm
vendored
Normal file
264
database/perl/vendor/lib/Convert/ASN1/IO.pm
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1;
|
||||
{
|
||||
$Convert::ASN1::VERSION = '0.27';
|
||||
}
|
||||
|
||||
use strict;
|
||||
use Socket;
|
||||
|
||||
BEGIN {
|
||||
local $SIG{__DIE__};
|
||||
eval { require bytes } and 'bytes'->import
|
||||
}
|
||||
|
||||
sub asn_recv { # $socket, $buffer, $flags
|
||||
|
||||
my $peer;
|
||||
my $buf;
|
||||
my $n = 128;
|
||||
my $pos = 0;
|
||||
my $depth = 0;
|
||||
my $len = 0;
|
||||
my($tmp,$tb,$lb);
|
||||
|
||||
MORE:
|
||||
for(
|
||||
$peer = recv($_[0],$buf,$n,MSG_PEEK);
|
||||
defined $peer;
|
||||
$peer = recv($_[0],$buf,$n<<=1,MSG_PEEK)
|
||||
) {
|
||||
|
||||
if ($depth) { # Are we searching of "\0\0"
|
||||
|
||||
unless (2+$pos <= length $buf) {
|
||||
next MORE if $n == length $buf;
|
||||
last MORE;
|
||||
}
|
||||
|
||||
if(substr($buf,$pos,2) eq "\0\0") {
|
||||
unless (--$depth) {
|
||||
$len = $pos + 2;
|
||||
last MORE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If we can decode a tag and length we can detemine the length
|
||||
($tb,$tmp) = asn_decode_tag(substr($buf,$pos));
|
||||
unless ($tb || $pos+$tb < length $buf) {
|
||||
next MORE if $n == length $buf;
|
||||
last MORE;
|
||||
}
|
||||
|
||||
if (unpack("C",substr($buf,$pos+$tb,1)) == 0x80) {
|
||||
# indefinite length, grrr!
|
||||
$depth++;
|
||||
$pos += $tb + 1;
|
||||
redo MORE;
|
||||
}
|
||||
|
||||
($lb,$len) = asn_decode_length(substr($buf,$pos+$tb));
|
||||
|
||||
if ($lb) {
|
||||
if ($depth) {
|
||||
$pos += $tb + $lb + $len;
|
||||
redo MORE;
|
||||
}
|
||||
else {
|
||||
$len += $tb + $lb + $pos;
|
||||
last MORE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $peer) {
|
||||
if ($len > length $buf) {
|
||||
# Check we can read the whole element
|
||||
goto error
|
||||
unless defined($peer = recv($_[0],$buf,$len,MSG_PEEK));
|
||||
|
||||
if ($len > length $buf) {
|
||||
# Cannot get whole element
|
||||
$_[1]='';
|
||||
return $peer;
|
||||
}
|
||||
}
|
||||
elsif ($len == 0) {
|
||||
$_[1] = '';
|
||||
return $peer;
|
||||
}
|
||||
|
||||
if ($_[2] & MSG_PEEK) {
|
||||
$_[1] = substr($buf,0,$len);
|
||||
}
|
||||
elsif (!defined($peer = recv($_[0],$_[1],$len,0))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return $peer;
|
||||
}
|
||||
|
||||
error:
|
||||
$_[1] = undef;
|
||||
}
|
||||
|
||||
sub asn_read { # $fh, $buffer, $offset
|
||||
|
||||
# We need to read one packet, and exactly only one packet.
|
||||
# So we have to read the first few bytes one at a time, until
|
||||
# we have enough to decode a tag and a length. We then know
|
||||
# how many more bytes to read
|
||||
|
||||
if ($_[2]) {
|
||||
if ($_[2] > length $_[1]) {
|
||||
require Carp;
|
||||
Carp::carp("Offset beyond end of buffer");
|
||||
return;
|
||||
}
|
||||
substr($_[1],$_[2]) = '';
|
||||
}
|
||||
else {
|
||||
$_[1] = '';
|
||||
}
|
||||
|
||||
my $pos = 0;
|
||||
my $need = 0;
|
||||
my $depth = 0;
|
||||
my $ch;
|
||||
my $n;
|
||||
my $e;
|
||||
|
||||
|
||||
while(1) {
|
||||
$need = ($pos + ($depth * 2)) || 2;
|
||||
|
||||
while(($n = $need - length $_[1]) > 0) {
|
||||
$e = sysread($_[0],$_[1],$n,length $_[1]) or
|
||||
goto READ_ERR;
|
||||
}
|
||||
|
||||
my $tch = unpack("C",substr($_[1],$pos++,1));
|
||||
# Tag may be multi-byte
|
||||
if(($tch & 0x1f) == 0x1f) {
|
||||
my $ch;
|
||||
do {
|
||||
$need++;
|
||||
while(($n = $need - length $_[1]) > 0) {
|
||||
$e = sysread($_[0],$_[1],$n,length $_[1]) or
|
||||
goto READ_ERR;
|
||||
}
|
||||
$ch = unpack("C",substr($_[1],$pos++,1));
|
||||
} while($ch & 0x80);
|
||||
}
|
||||
|
||||
$need = $pos + 1;
|
||||
|
||||
while(($n = $need - length $_[1]) > 0) {
|
||||
$e = sysread($_[0],$_[1],$n,length $_[1]) or
|
||||
goto READ_ERR;
|
||||
}
|
||||
|
||||
my $len = unpack("C",substr($_[1],$pos++,1));
|
||||
|
||||
if($len & 0x80) {
|
||||
unless ($len &= 0x7f) {
|
||||
$depth++;
|
||||
next;
|
||||
}
|
||||
$need = $pos + $len;
|
||||
|
||||
while(($n = $need - length $_[1]) > 0) {
|
||||
$e = sysread($_[0],$_[1],$n,length $_[1]) or
|
||||
goto READ_ERR;
|
||||
}
|
||||
|
||||
$pos += $len + unpack("N", "\0" x (4 - $len) . substr($_[1],$pos,$len));
|
||||
}
|
||||
elsif (!$len && !$tch) {
|
||||
die "Bad ASN PDU" unless $depth;
|
||||
unless (--$depth) {
|
||||
last;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$pos += $len;
|
||||
}
|
||||
|
||||
last unless $depth;
|
||||
}
|
||||
|
||||
while(($n = $pos - length $_[1]) > 0) {
|
||||
$e = sysread($_[0],$_[1],$n,length $_[1]) or
|
||||
goto READ_ERR;
|
||||
}
|
||||
|
||||
return length $_[1];
|
||||
|
||||
READ_ERR:
|
||||
$@ = defined($e) ? "Unexpected EOF" : "I/O Error $!"; # . CORE::unpack("H*",$_[1]);
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub asn_send { # $sock, $buffer, $flags, $to
|
||||
|
||||
@_ == 4
|
||||
? send($_[0],$_[1],$_[2],$_[3])
|
||||
: send($_[0],$_[1],$_[2]);
|
||||
}
|
||||
|
||||
sub asn_write { # $sock, $buffer
|
||||
|
||||
syswrite($_[0],$_[1], length $_[1]);
|
||||
}
|
||||
|
||||
sub asn_get { # $fh
|
||||
|
||||
my $fh = ref($_[0]) ? $_[0] : \($_[0]);
|
||||
my $href = \%{*$fh};
|
||||
|
||||
$href->{'asn_buffer'} = '' unless exists $href->{'asn_buffer'};
|
||||
|
||||
my $need = delete $href->{'asn_need'} || 0;
|
||||
while(1) {
|
||||
next if $need;
|
||||
my($tb,$tag) = asn_decode_tag($href->{'asn_buffer'}) or next;
|
||||
my($lb,$len) = asn_decode_length(substr($href->{'asn_buffer'},$tb,8)) or next;
|
||||
$need = $tb + $lb + $len;
|
||||
}
|
||||
continue {
|
||||
if ($need && $need <= length $href->{'asn_buffer'}) {
|
||||
my $ret = substr($href->{'asn_buffer'},0,$need);
|
||||
substr($href->{'asn_buffer'},0,$need) = '';
|
||||
return $ret;
|
||||
}
|
||||
|
||||
my $get = $need > 1024 ? $need : 1024;
|
||||
|
||||
sysread($_[0], $href->{'asn_buffer'}, $get, length $href->{'asn_buffer'})
|
||||
or return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub asn_ready { # $fh
|
||||
|
||||
my $fh = ref($_[0]) ? $_[0] : \($_[0]);
|
||||
my $href = \%{*$fh};
|
||||
|
||||
return 0 unless exists $href->{'asn_buffer'};
|
||||
|
||||
return $href->{'asn_need'} <= length $href->{'asn_buffer'}
|
||||
if exists $href->{'asn_need'};
|
||||
|
||||
my($tb,$tag) = asn_decode_tag($href->{'asn_buffer'}) or return 0;
|
||||
my($lb,$len) = asn_decode_length(substr($href->{'asn_buffer'},$tb,8)) or return 0;
|
||||
|
||||
$href->{'asn_need'} = $tb + $lb + $len;
|
||||
|
||||
$href->{'asn_need'} <= length $href->{'asn_buffer'};
|
||||
}
|
||||
|
||||
1;
|
||||
734
database/perl/vendor/lib/Convert/ASN1/_decode.pm
vendored
Normal file
734
database/perl/vendor/lib/Convert/ASN1/_decode.pm
vendored
Normal file
@@ -0,0 +1,734 @@
|
||||
# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1;
|
||||
{
|
||||
$Convert::ASN1::VERSION = '0.27';
|
||||
}
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
local $SIG{__DIE__};
|
||||
eval { require bytes and 'bytes'->import };
|
||||
}
|
||||
|
||||
# These are the subs that do the decode, they are called with
|
||||
# 0 1 2 3 4
|
||||
# $optn, $op, $stash, $var, $buf
|
||||
# The order must be the same as the op definitions above
|
||||
|
||||
my @decode = (
|
||||
sub { die "internal error\n" },
|
||||
\&_dec_boolean,
|
||||
\&_dec_integer,
|
||||
\&_dec_bitstring,
|
||||
\&_dec_string,
|
||||
\&_dec_null,
|
||||
\&_dec_object_id,
|
||||
\&_dec_real,
|
||||
\&_dec_sequence,
|
||||
\&_dec_explicit,
|
||||
\&_dec_set,
|
||||
\&_dec_time,
|
||||
\&_dec_time,
|
||||
\&_dec_utf8,
|
||||
undef, # ANY
|
||||
undef, # CHOICE
|
||||
\&_dec_object_id,
|
||||
\&_dec_bcd,
|
||||
);
|
||||
|
||||
my @ctr;
|
||||
@ctr[opBITSTR, opSTRING, opUTF8] = (\&_ctr_bitstring,\&_ctr_string,\&_ctr_string);
|
||||
|
||||
|
||||
sub _decode {
|
||||
my ($optn, $ops, $stash, $pos, $end, $seqof, $larr) = @_;
|
||||
my $idx = 0;
|
||||
|
||||
# we try not to copy the input buffer at any time
|
||||
foreach my $buf ($_[-1]) {
|
||||
OP:
|
||||
foreach my $op (@{$ops}) {
|
||||
my $var = $op->[cVAR];
|
||||
|
||||
if (length $op->[cTAG]) {
|
||||
|
||||
TAGLOOP: {
|
||||
my($tag,$len,$npos,$indef) = _decode_tl($buf,$pos,$end,$larr)
|
||||
or do {
|
||||
next OP if $pos==$end and ($seqof || defined $op->[cEXT]);
|
||||
die "decode error";
|
||||
};
|
||||
|
||||
if ($tag eq $op->[cTAG]) {
|
||||
|
||||
&{$decode[$op->[cTYPE]]}(
|
||||
$optn,
|
||||
$op,
|
||||
$stash,
|
||||
# We send 1 if there is not var as if there is the decode
|
||||
# should be getting undef. So if it does not get undef
|
||||
# it knows it has no variable
|
||||
($seqof ? $seqof->[$idx++] : defined($var) ? $stash->{$var} : ref($stash) eq 'SCALAR' ? $$stash : 1),
|
||||
$buf,$npos,$len, $larr
|
||||
);
|
||||
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo TAGLOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
}
|
||||
|
||||
if ($tag eq ($op->[cTAG] | pack("C",ASN_CONSTRUCTOR))
|
||||
and my $ctr = $ctr[$op->[cTYPE]])
|
||||
{
|
||||
_decode(
|
||||
$optn,
|
||||
[$op],
|
||||
undef,
|
||||
$npos,
|
||||
$npos+$len,
|
||||
(\my @ctrlist),
|
||||
$larr,
|
||||
$buf,
|
||||
);
|
||||
|
||||
($seqof ? $seqof->[$idx++] : defined($var) ? $stash->{$var} : ref($stash) eq 'SCALAR' ? $$stash : undef)
|
||||
= &{$ctr}(@ctrlist);
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo TAGLOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
|
||||
}
|
||||
|
||||
if ($seqof || defined $op->[cEXT]) {
|
||||
next OP;
|
||||
}
|
||||
|
||||
die "decode error " . unpack("H*",$tag) ."<=>" . unpack("H*",$op->[cTAG]), " ",$pos," ",$op->[cTYPE]," ",$op->[cVAR]||'';
|
||||
}
|
||||
}
|
||||
else { # opTag length is zero, so it must be an ANY, CHOICE or EXTENSIONS
|
||||
|
||||
if ($op->[cTYPE] == opANY) {
|
||||
|
||||
ANYLOOP: {
|
||||
|
||||
my($tag,$len,$npos,$indef) = _decode_tl($buf,$pos,$end,$larr)
|
||||
or do {
|
||||
next OP if $pos==$end and ($seqof || defined $op->[cEXT]);
|
||||
die "decode error";
|
||||
};
|
||||
|
||||
$len += $npos - $pos + $indef;
|
||||
|
||||
my $handler;
|
||||
if ($op->[cDEFINE]) {
|
||||
$handler = $optn->{oidtable} && $optn->{oidtable}{$stash->{$op->[cDEFINE]}};
|
||||
$handler ||= $optn->{handlers}{$op->[cVAR]}{$stash->{$op->[cDEFINE]}};
|
||||
}
|
||||
|
||||
($seqof ? $seqof->[$idx++] : ref($stash) eq 'SCALAR' ? $$stash : $stash->{$var})
|
||||
= $handler ? $handler->decode(substr($buf,$pos,$len)) : substr($buf,$pos,$len);
|
||||
|
||||
$pos += $len;
|
||||
|
||||
redo ANYLOOP if $seqof && $pos < $end;
|
||||
}
|
||||
}
|
||||
elsif ($op->[cTYPE] == opCHOICE) {
|
||||
|
||||
CHOICELOOP: {
|
||||
my($tag,$len,$npos,$indef) = _decode_tl($buf,$pos,$end,$larr)
|
||||
or do {
|
||||
next OP if $pos==$end and ($seqof || defined $op->[cEXT]);
|
||||
die "decode error";
|
||||
};
|
||||
my $extensions;
|
||||
foreach my $cop (@{$op->[cCHILD]}) {
|
||||
|
||||
if ($tag eq $cop->[cTAG]) {
|
||||
|
||||
my $nstash = $seqof
|
||||
? ($seqof->[$idx++]={})
|
||||
: defined($var)
|
||||
? ($stash->{$var}={})
|
||||
: ref($stash) eq 'SCALAR'
|
||||
? ($$stash={}) : $stash;
|
||||
|
||||
&{$decode[$cop->[cTYPE]]}(
|
||||
$optn,
|
||||
$cop,
|
||||
$nstash,
|
||||
($cop->[cVAR] ? $nstash->{$cop->[cVAR]} : undef),
|
||||
$buf,$npos,$len,$larr,
|
||||
);
|
||||
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo CHOICELOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
}
|
||||
|
||||
if ($cop->[cTYPE] == opEXTENSIONS) {
|
||||
$extensions = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
unless (length $cop->[cTAG]) {
|
||||
eval {
|
||||
_decode(
|
||||
$optn,
|
||||
[$cop],
|
||||
(\my %tmp_stash),
|
||||
$pos,
|
||||
$npos+$len+$indef,
|
||||
undef,
|
||||
$larr,
|
||||
$buf,
|
||||
);
|
||||
|
||||
my $nstash = $seqof
|
||||
? ($seqof->[$idx++]={})
|
||||
: defined($var)
|
||||
? ($stash->{$var}={})
|
||||
: ref($stash) eq 'SCALAR'
|
||||
? ($$stash={}) : $stash;
|
||||
|
||||
@{$nstash}{keys %tmp_stash} = values %tmp_stash;
|
||||
|
||||
} or next;
|
||||
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo CHOICELOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
}
|
||||
|
||||
if ($tag eq ($cop->[cTAG] | pack("C",ASN_CONSTRUCTOR))
|
||||
and my $ctr = $ctr[$cop->[cTYPE]])
|
||||
{
|
||||
my $nstash = $seqof
|
||||
? ($seqof->[$idx++]={})
|
||||
: defined($var)
|
||||
? ($stash->{$var}={})
|
||||
: ref($stash) eq 'SCALAR'
|
||||
? ($$stash={}) : $stash;
|
||||
|
||||
_decode(
|
||||
$optn,
|
||||
[$cop],
|
||||
undef,
|
||||
$npos,
|
||||
$npos+$len,
|
||||
(\my @ctrlist),
|
||||
$larr,
|
||||
$buf,
|
||||
);
|
||||
|
||||
$nstash->{$cop->[cVAR]} = &{$ctr}(@ctrlist);
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo CHOICELOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
}
|
||||
}
|
||||
|
||||
if ($pos < $end && $extensions) {
|
||||
$pos = $npos+$len+$indef;
|
||||
|
||||
redo CHOICELOOP if $seqof && $pos < $end;
|
||||
next OP;
|
||||
}
|
||||
}
|
||||
die "decode error" unless $op->[cEXT];
|
||||
}
|
||||
elsif ($op->[cTYPE] == opEXTENSIONS) {
|
||||
$pos = $end; # Skip over the rest
|
||||
}
|
||||
else {
|
||||
die "this point should never be reached";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
die "decode error $pos $end" unless $pos == $end;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_boolean {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
$_[3] = unpack("C",substr($_[4],$_[5],1)) ? 1 : 0;
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_integer {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
my $buf = substr($_[4],$_[5],$_[6]);
|
||||
my $tmp = unpack("C",$buf) & 0x80 ? pack("C",255) : pack("C",0);
|
||||
if ($_[6] > 4) {
|
||||
$_[3] = os2ip($buf, $_[0]->{decode_bigint} || 'Math::BigInt');
|
||||
} else {
|
||||
# N unpacks an unsigned value
|
||||
$_[3] = unpack("l",pack("l",unpack("N", $tmp x (4-$_[6]) . $buf)));
|
||||
}
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_bitstring {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
$_[3] = [ substr($_[4],$_[5]+1,$_[6]-1), ($_[6]-1)*8-unpack("C",substr($_[4],$_[5],1)) ];
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_string {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
$_[3] = substr($_[4],$_[5],$_[6]);
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_null {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
$_[3] = exists($_[0]->{decode_null}) ? $_[0]->{decode_null} : 1;
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_object_id {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
my @data = unpack("w*",substr($_[4],$_[5],$_[6]));
|
||||
if ($_[1]->[cTYPE] == opOBJID and @data > 1) {
|
||||
if ($data[0] < 40) {
|
||||
splice(@data, 0, 1, 0, $data[0]);
|
||||
}
|
||||
elsif ($data[0] < 80) {
|
||||
splice(@data, 0, 1, 1, $data[0] - 40);
|
||||
}
|
||||
else {
|
||||
splice(@data, 0, 1, 2, $data[0] - 80);
|
||||
}
|
||||
}
|
||||
$_[3] = join(".", @data);
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
my @_dec_real_base = (2,8,16);
|
||||
|
||||
sub _dec_real {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
$_[3] = 0.0, return unless $_[6];
|
||||
|
||||
my $first = unpack("C",substr($_[4],$_[5],1));
|
||||
if ($first & 0x80) {
|
||||
# A real number
|
||||
|
||||
require POSIX;
|
||||
|
||||
my $exp;
|
||||
my $expLen = $first & 0x3;
|
||||
my $estart = $_[5]+1;
|
||||
|
||||
if($expLen == 3) {
|
||||
$estart++;
|
||||
$expLen = unpack("C",substr($_[4],$_[5]+1,1));
|
||||
}
|
||||
else {
|
||||
$expLen++;
|
||||
}
|
||||
_dec_integer(undef, undef, undef, $exp, $_[4],$estart,$expLen);
|
||||
|
||||
my $mant = 0.0;
|
||||
for (reverse unpack("C*",substr($_[4],$estart+$expLen,$_[6]-1-$expLen))) {
|
||||
$exp +=8, $mant = (($mant+$_) / 256) ;
|
||||
}
|
||||
|
||||
$mant *= 1 << (($first >> 2) & 0x3);
|
||||
$mant = - $mant if $first & 0x40;
|
||||
|
||||
$_[3] = $mant * POSIX::pow($_dec_real_base[($first >> 4) & 0x3], $exp);
|
||||
return;
|
||||
}
|
||||
elsif($first & 0x40) {
|
||||
$_[3] = POSIX::HUGE_VAL(),return if $first == 0x40;
|
||||
$_[3] = - POSIX::HUGE_VAL(),return if $first == 0x41;
|
||||
}
|
||||
elsif(substr($_[4],$_[5],$_[6]) =~ /^.([-+]?)0*(\d+(?:\.\d+(?:[Ee][-+]?\d+)?)?)$/s) {
|
||||
$_[3] = eval "$1$2";
|
||||
return;
|
||||
}
|
||||
|
||||
die "REAL decode error\n";
|
||||
}
|
||||
|
||||
|
||||
sub _dec_explicit {
|
||||
# 0 1 2 3 4 5 6 7
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len, $larr
|
||||
|
||||
local $_[1][cCHILD][0][cVAR] = $_[1][cVAR] unless $_[1][cCHILD][0][cVAR];
|
||||
|
||||
_decode(
|
||||
$_[0], #optn
|
||||
$_[1]->[cCHILD], #ops
|
||||
$_[2], #stash
|
||||
$_[5], #pos
|
||||
$_[5]+$_[6], #end
|
||||
undef, #loop
|
||||
$_[7],
|
||||
$_[4], #buf
|
||||
);
|
||||
1;
|
||||
}
|
||||
sub _dec_sequence {
|
||||
# 0 1 2 3 4 5 6 7
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len, $larr
|
||||
|
||||
if (defined( my $ch = $_[1]->[cCHILD])) {
|
||||
_decode(
|
||||
$_[0], #optn
|
||||
$ch, #ops
|
||||
(defined($_[3]) || $_[1]->[cLOOP]) ? $_[2] : ($_[3]= {}), #stash
|
||||
$_[5], #pos
|
||||
$_[5]+$_[6], #end
|
||||
$_[1]->[cLOOP] && ($_[3]=[]), #loop
|
||||
$_[7],
|
||||
$_[4], #buf
|
||||
);
|
||||
}
|
||||
else {
|
||||
$_[3] = substr($_[4],$_[5],$_[6]);
|
||||
}
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_set {
|
||||
# 0 1 2 3 4 5 6 7
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len, $larr
|
||||
|
||||
# decode SET OF the same as SEQUENCE OF
|
||||
my $ch = $_[1]->[cCHILD];
|
||||
goto &_dec_sequence if $_[1]->[cLOOP] or !defined($ch);
|
||||
|
||||
my ($optn, $pos, $larr) = @_[0,5,7];
|
||||
my $stash = defined($_[3]) ? $_[2] : ($_[3]={});
|
||||
my $end = $pos + $_[6];
|
||||
my @done;
|
||||
my $extensions;
|
||||
|
||||
while ($pos < $end) {
|
||||
my($tag,$len,$npos,$indef) = _decode_tl($_[4],$pos,$end,$larr)
|
||||
or die "decode error";
|
||||
|
||||
my ($idx, $any, $done) = (-1);
|
||||
|
||||
SET_OP:
|
||||
foreach my $op (@$ch) {
|
||||
$idx++;
|
||||
if (length($op->[cTAG])) {
|
||||
if ($tag eq $op->[cTAG]) {
|
||||
my $var = $op->[cVAR];
|
||||
&{$decode[$op->[cTYPE]]}(
|
||||
$optn,
|
||||
$op,
|
||||
$stash,
|
||||
# We send 1 if there is not var as if there is the decode
|
||||
# should be getting undef. So if it does not get undef
|
||||
# it knows it has no variable
|
||||
(defined($var) ? $stash->{$var} : 1),
|
||||
$_[4],$npos,$len,$larr,
|
||||
);
|
||||
$done = $idx;
|
||||
last SET_OP;
|
||||
}
|
||||
if ($tag eq ($op->[cTAG] | pack("C",ASN_CONSTRUCTOR))
|
||||
and my $ctr = $ctr[$op->[cTYPE]])
|
||||
{
|
||||
_decode(
|
||||
$optn,
|
||||
[$op],
|
||||
undef,
|
||||
$npos,
|
||||
$npos+$len,
|
||||
(\my @ctrlist),
|
||||
$larr,
|
||||
$_[4],
|
||||
);
|
||||
|
||||
$stash->{$op->[cVAR]} = &{$ctr}(@ctrlist)
|
||||
if defined $op->[cVAR];
|
||||
$done = $idx;
|
||||
last SET_OP;
|
||||
}
|
||||
next SET_OP;
|
||||
}
|
||||
elsif ($op->[cTYPE] == opANY) {
|
||||
$any = $idx;
|
||||
}
|
||||
elsif ($op->[cTYPE] == opCHOICE) {
|
||||
my $var = $op->[cVAR];
|
||||
foreach my $cop (@{$op->[cCHILD]}) {
|
||||
if ($tag eq $cop->[cTAG]) {
|
||||
my $nstash = defined($var) ? ($stash->{$var}={}) : $stash;
|
||||
|
||||
&{$decode[$cop->[cTYPE]]}(
|
||||
$optn,
|
||||
$cop,
|
||||
$nstash,
|
||||
$nstash->{$cop->[cVAR]},
|
||||
$_[4],$npos,$len,$larr,
|
||||
);
|
||||
$done = $idx;
|
||||
last SET_OP;
|
||||
}
|
||||
if ($tag eq ($cop->[cTAG] | pack("C",ASN_CONSTRUCTOR))
|
||||
and my $ctr = $ctr[$cop->[cTYPE]])
|
||||
{
|
||||
my $nstash = defined($var) ? ($stash->{$var}={}) : $stash;
|
||||
|
||||
_decode(
|
||||
$optn,
|
||||
[$cop],
|
||||
undef,
|
||||
$npos,
|
||||
$npos+$len,
|
||||
(\my @ctrlist),
|
||||
$larr,
|
||||
$_[4],
|
||||
);
|
||||
|
||||
$nstash->{$cop->[cVAR]} = &{$ctr}(@ctrlist);
|
||||
$done = $idx;
|
||||
last SET_OP;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($op->[cTYPE] == opEXTENSIONS) {
|
||||
$extensions = $idx;
|
||||
}
|
||||
else {
|
||||
die "internal error";
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined($done) and defined($any)) {
|
||||
my $var = $ch->[$any][cVAR];
|
||||
$stash->{$var} = substr($_[4],$pos,$len+$npos-$pos) if defined $var;
|
||||
$done = $any;
|
||||
}
|
||||
|
||||
if( !defined($done) && defined($extensions) ) {
|
||||
$done = $extensions;
|
||||
}
|
||||
|
||||
die "decode error" if !defined($done) or $done[$done]++;
|
||||
|
||||
$pos = $npos + $len + $indef;
|
||||
}
|
||||
|
||||
die "decode error" unless $end == $pos;
|
||||
|
||||
foreach my $idx (0..$#{$ch}) {
|
||||
die "decode error" unless $done[$idx] or $ch->[$idx][cEXT] or $ch->[$idx][cTYPE] == opEXTENSIONS;
|
||||
}
|
||||
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
my %_dec_time_opt = ( unixtime => 0, withzone => 1, raw => 2);
|
||||
|
||||
sub _dec_time {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
my $mode = $_dec_time_opt{$_[0]->{'decode_time'} || ''} || 0;
|
||||
|
||||
if ($mode == 2 or $_[6] == 0) {
|
||||
$_[3] = substr($_[4],$_[5],$_[6]);
|
||||
return;
|
||||
}
|
||||
|
||||
my @bits = (substr($_[4],$_[5],$_[6])
|
||||
=~ /^((?:\d\d)?\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)((?:\.\d{1,3})?)(([-+])(\d\d)(\d\d)|Z)/)
|
||||
or die "bad time format";
|
||||
|
||||
if ($bits[0] < 100) {
|
||||
$bits[0] += 100 if $bits[0] < 50;
|
||||
}
|
||||
else {
|
||||
$bits[0] -= 1900;
|
||||
}
|
||||
$bits[1] -= 1;
|
||||
require Time::Local;
|
||||
my $time = Time::Local::timegm(@bits[5,4,3,2,1,0]);
|
||||
$time += $bits[6] if length $bits[6];
|
||||
my $offset = 0;
|
||||
if ($bits[7] ne 'Z') {
|
||||
$offset = $bits[9] * 3600 + $bits[10] * 60;
|
||||
$offset = -$offset if $bits[8] eq '-';
|
||||
$time -= $offset;
|
||||
}
|
||||
$_[3] = $mode ? [$time,$offset] : $time;
|
||||
}
|
||||
|
||||
|
||||
sub _dec_utf8 {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
BEGIN {
|
||||
unless (CHECK_UTF8) {
|
||||
local $SIG{__DIE__};
|
||||
eval { require bytes } and 'bytes'->unimport;
|
||||
eval { require utf8 } and 'utf8'->import;
|
||||
}
|
||||
}
|
||||
|
||||
if (CHECK_UTF8) {
|
||||
$_[3] = Encode::decode('utf8', substr($_[4],$_[5],$_[6]));
|
||||
}
|
||||
else {
|
||||
$_[3] = (substr($_[4],$_[5],$_[6]) =~ /(.*)/s)[0];
|
||||
}
|
||||
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
sub _decode_tl {
|
||||
my($pos,$end,$larr) = @_[1,2,3];
|
||||
|
||||
return if $pos >= $end;
|
||||
|
||||
my $indef = 0;
|
||||
|
||||
my $tag = substr($_[0], $pos++, 1);
|
||||
|
||||
if((unpack("C",$tag) & 0x1f) == 0x1f) {
|
||||
my $b;
|
||||
my $n=1;
|
||||
do {
|
||||
return if $pos >= $end;
|
||||
$tag .= substr($_[0],$pos++,1);
|
||||
$b = ord substr($tag,-1);
|
||||
} while($b & 0x80);
|
||||
}
|
||||
return if $pos >= $end;
|
||||
|
||||
my $len = ord substr($_[0],$pos++,1);
|
||||
|
||||
if($len & 0x80) {
|
||||
$len &= 0x7f;
|
||||
|
||||
if ($len) {
|
||||
return if $pos+$len > $end ;
|
||||
|
||||
my $padding = $len < 4 ? "\0" x (4 - $len) : "";
|
||||
($len,$pos) = (unpack("N", $padding . substr($_[0],$pos,$len)), $pos+$len);
|
||||
}
|
||||
else {
|
||||
unless (exists $larr->{$pos}) {
|
||||
_scan_indef($_[0],$pos,$end,$larr) or return;
|
||||
}
|
||||
$indef = 2;
|
||||
$len = $larr->{$pos};
|
||||
}
|
||||
}
|
||||
|
||||
return if $pos+$len+$indef > $end;
|
||||
|
||||
# return the tag, the length of the data, the position of the data
|
||||
# and the number of extra bytes for indefinate encoding
|
||||
|
||||
($tag, $len, $pos, $indef);
|
||||
}
|
||||
|
||||
sub _scan_indef {
|
||||
my($pos,$end,$larr) = @_[1,2,3];
|
||||
my @depth = ( $pos );
|
||||
|
||||
while(@depth) {
|
||||
return if $pos+2 > $end;
|
||||
|
||||
if (substr($_[0],$pos,2) eq "\0\0") {
|
||||
my $end = $pos;
|
||||
my $stref = shift @depth;
|
||||
# replace pos with length = end - pos
|
||||
$larr->{$stref} = $end - $stref;
|
||||
$pos += 2;
|
||||
next;
|
||||
}
|
||||
|
||||
my $tag = substr($_[0], $pos++, 1);
|
||||
|
||||
if((unpack("C",$tag) & 0x1f) == 0x1f) {
|
||||
my $b;
|
||||
do {
|
||||
$tag .= substr($_[0],$pos++,1);
|
||||
$b = ord substr($tag,-1);
|
||||
} while($b & 0x80);
|
||||
}
|
||||
return if $pos >= $end;
|
||||
|
||||
my $len = ord substr($_[0],$pos++,1);
|
||||
|
||||
if($len & 0x80) {
|
||||
if ($len &= 0x7f) {
|
||||
return if $pos+$len > $end ;
|
||||
|
||||
my $padding = $len < 4 ? "\0" x (4 - $len) : "";
|
||||
$pos += $len + unpack("N", $padding . substr($_[0],$pos,$len));
|
||||
}
|
||||
else {
|
||||
# reserve another list element
|
||||
unshift @depth, $pos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$pos += $len;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
}
|
||||
|
||||
sub _ctr_string { join '', @_ }
|
||||
|
||||
sub _ctr_bitstring {
|
||||
[ join('', map { $_->[0] } @_), $_[-1]->[1] ]
|
||||
}
|
||||
|
||||
sub _dec_bcd {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $pos, $len
|
||||
|
||||
($_[3] = unpack("H*", substr($_[4],$_[5],$_[6]))) =~ s/[fF]$//;
|
||||
1;
|
||||
}
|
||||
1;
|
||||
|
||||
416
database/perl/vendor/lib/Convert/ASN1/_encode.pm
vendored
Normal file
416
database/perl/vendor/lib/Convert/ASN1/_encode.pm
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1;
|
||||
{
|
||||
$Convert::ASN1::VERSION = '0.27';
|
||||
}
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
unless (CHECK_UTF8) {
|
||||
local $SIG{__DIE__};
|
||||
eval { require bytes } and 'bytes'->import
|
||||
}
|
||||
}
|
||||
|
||||
# These are the subs which do the encoding, they are called with
|
||||
# 0 1 2 3 4 5
|
||||
# $opt, $op, $stash, $var, $buf, $loop
|
||||
# The order in the array must match the op definitions above
|
||||
|
||||
my @encode = (
|
||||
sub { die "internal error\n" },
|
||||
\&_enc_boolean,
|
||||
\&_enc_integer,
|
||||
\&_enc_bitstring,
|
||||
\&_enc_string,
|
||||
\&_enc_null,
|
||||
\&_enc_object_id,
|
||||
\&_enc_real,
|
||||
\&_enc_sequence,
|
||||
\&_enc_sequence, # EXPLICIT is the same encoding as sequence
|
||||
\&_enc_sequence, # SET is the same encoding as sequence
|
||||
\&_enc_time,
|
||||
\&_enc_time,
|
||||
\&_enc_utf8,
|
||||
\&_enc_any,
|
||||
\&_enc_choice,
|
||||
\&_enc_object_id,
|
||||
\&_enc_bcd,
|
||||
);
|
||||
|
||||
|
||||
sub _encode {
|
||||
my ($optn, $ops, $stash, $path) = @_;
|
||||
my $var;
|
||||
|
||||
foreach my $op (@{$ops}) {
|
||||
next if $op->[cTYPE] == opEXTENSIONS;
|
||||
if (defined(my $opt = $op->[cOPT])) {
|
||||
next unless defined $stash->{$opt};
|
||||
}
|
||||
if (defined($var = $op->[cVAR])) {
|
||||
push @$path, $var;
|
||||
require Carp, Carp::croak(join(".", @$path)," is undefined") unless defined $stash->{$var};
|
||||
}
|
||||
$_[4] .= $op->[cTAG];
|
||||
|
||||
&{$encode[$op->[cTYPE]]}(
|
||||
$optn,
|
||||
$op,
|
||||
(UNIVERSAL::isa($stash, 'HASH')
|
||||
? ($stash, defined($var) ? $stash->{$var} : undef)
|
||||
: ({}, $stash)),
|
||||
$_[4],
|
||||
$op->[cLOOP],
|
||||
$path,
|
||||
);
|
||||
|
||||
pop @$path if defined $var;
|
||||
}
|
||||
|
||||
$_[4];
|
||||
}
|
||||
|
||||
|
||||
sub _enc_boolean {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
$_[4] .= pack("CC",1, $_[3] ? 0xff : 0);
|
||||
}
|
||||
|
||||
|
||||
sub _enc_integer {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
if (abs($_[3]) >= 2**31) {
|
||||
my $os = i2osp($_[3], ref($_[3]) || $_[0]->{encode_bigint} || 'Math::BigInt');
|
||||
my $len = length $os;
|
||||
my $msb = (vec($os, 0, 8) & 0x80) ? 0 : 255;
|
||||
$len++, $os = pack("C",$msb) . $os if $msb xor $_[3] > 0;
|
||||
$_[4] .= asn_encode_length($len);
|
||||
$_[4] .= $os;
|
||||
}
|
||||
else {
|
||||
my $val = int($_[3]);
|
||||
my $neg = ($val < 0);
|
||||
my $len = num_length($neg ? ~$val : $val);
|
||||
my $msb = $val & (0x80 << (($len - 1) * 8));
|
||||
|
||||
$len++ if $neg ? !$msb : $msb;
|
||||
|
||||
$_[4] .= asn_encode_length($len);
|
||||
$_[4] .= substr(pack("N",$val), -$len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _enc_bitstring {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
my $vref = ref($_[3]) ? \($_[3]->[0]) : \$_[3];
|
||||
|
||||
if (CHECK_UTF8 and Encode::is_utf8($$vref)) {
|
||||
utf8::encode(my $tmp = $$vref);
|
||||
$vref = \$tmp;
|
||||
}
|
||||
|
||||
if (ref($_[3])) {
|
||||
my $less = (8 - ($_[3]->[1] & 7)) & 7;
|
||||
my $len = ($_[3]->[1] + 7) >> 3;
|
||||
$_[4] .= asn_encode_length(1+$len);
|
||||
$_[4] .= pack("C",$less);
|
||||
$_[4] .= substr($$vref, 0, $len);
|
||||
if ($less && $len) {
|
||||
substr($_[4],-1) &= pack("C",(0xff << $less) & 0xff);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_[4] .= asn_encode_length(1+length $$vref);
|
||||
$_[4] .= pack("C",0);
|
||||
$_[4] .= $$vref;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _enc_string {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
if (CHECK_UTF8 and Encode::is_utf8($_[3])) {
|
||||
utf8::encode(my $tmp = $_[3]);
|
||||
$_[4] .= asn_encode_length(length $tmp);
|
||||
$_[4] .= $tmp;
|
||||
}
|
||||
else {
|
||||
$_[4] .= asn_encode_length(length $_[3]);
|
||||
$_[4] .= $_[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _enc_null {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
$_[4] .= pack("C",0);
|
||||
}
|
||||
|
||||
|
||||
sub _enc_object_id {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
my @data = ($_[3] =~ /(\d+)/g);
|
||||
|
||||
if ($_[1]->[cTYPE] == opOBJID) {
|
||||
if(@data < 2) {
|
||||
@data = (0);
|
||||
}
|
||||
else {
|
||||
my $first = $data[1] + ($data[0] * 40);
|
||||
splice(@data,0,2,$first);
|
||||
}
|
||||
}
|
||||
|
||||
my $l = length $_[4];
|
||||
$_[4] .= pack("cw*", 0, @data);
|
||||
substr($_[4],$l,1) = asn_encode_length(length($_[4]) - $l - 1);
|
||||
}
|
||||
|
||||
|
||||
sub _enc_real {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
# Zero
|
||||
unless ($_[3]) {
|
||||
$_[4] .= pack("C",0);
|
||||
return;
|
||||
}
|
||||
|
||||
require POSIX;
|
||||
|
||||
# +oo (well we use HUGE_VAL as Infinity is not avaliable to perl)
|
||||
if ($_[3] >= POSIX::HUGE_VAL()) {
|
||||
$_[4] .= pack("C*",0x01,0x40);
|
||||
return;
|
||||
}
|
||||
|
||||
# -oo (well we use HUGE_VAL as Infinity is not avaliable to perl)
|
||||
if ($_[3] <= - POSIX::HUGE_VAL()) {
|
||||
$_[4] .= pack("C*",0x01,0x41);
|
||||
return;
|
||||
}
|
||||
|
||||
if (exists $_[0]->{'encode_real'} && $_[0]->{'encode_real'} ne 'binary') {
|
||||
my $tmp = sprintf("%g",$_[3]);
|
||||
$_[4] .= asn_encode_length(1+length $tmp);
|
||||
$_[4] .= pack("C",1); # NR1?
|
||||
$_[4] .= $tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
# We have a real number.
|
||||
my $first = 0x80;
|
||||
my($mantissa, $exponent) = POSIX::frexp($_[3]);
|
||||
|
||||
if ($mantissa < 0.0) {
|
||||
$mantissa = -$mantissa;
|
||||
$first |= 0x40;
|
||||
}
|
||||
my($eMant,$eExp);
|
||||
|
||||
while($mantissa > 0.0) {
|
||||
($mantissa, my $int) = POSIX::modf($mantissa * (1<<8));
|
||||
$eMant .= pack("C",$int);
|
||||
}
|
||||
$exponent -= 8 * length $eMant;
|
||||
|
||||
_enc_integer(undef, undef, undef, $exponent, $eExp);
|
||||
|
||||
# $eExp will br prefixed by a length byte
|
||||
|
||||
if (5 > length $eExp) {
|
||||
$eExp =~ s/\A.//s;
|
||||
$first |= length($eExp)-1;
|
||||
}
|
||||
else {
|
||||
$first |= 0x3;
|
||||
}
|
||||
|
||||
$_[4] .= asn_encode_length(1 + length($eMant) + length($eExp));
|
||||
$_[4] .= pack("C",$first);
|
||||
$_[4] .= $eExp;
|
||||
$_[4] .= $eMant;
|
||||
}
|
||||
|
||||
|
||||
sub _enc_sequence {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
if (my $ops = $_[1]->[cCHILD]) {
|
||||
my $l = length $_[4];
|
||||
$_[4] .= "\0\0"; # guess
|
||||
if (defined $_[5]) {
|
||||
my $op = $ops->[0]; # there should only be one
|
||||
my $enc = $encode[$op->[cTYPE]];
|
||||
my $tag = $op->[cTAG];
|
||||
my $loop = $op->[cLOOP];
|
||||
|
||||
push @{$_[6]}, -1;
|
||||
|
||||
foreach my $var (@{$_[3]}) {
|
||||
$_[6]->[-1]++;
|
||||
$_[4] .= $tag;
|
||||
|
||||
&{$enc}(
|
||||
$_[0], # $optn
|
||||
$op, # $op
|
||||
$_[2], # $stash
|
||||
$var, # $var
|
||||
$_[4], # $buf
|
||||
$loop, # $loop
|
||||
$_[6], # $path
|
||||
);
|
||||
}
|
||||
pop @{$_[6]};
|
||||
}
|
||||
else {
|
||||
_encode($_[0],$_[1]->[cCHILD], defined($_[3]) ? $_[3] : $_[2], $_[6], $_[4]);
|
||||
}
|
||||
substr($_[4],$l,2) = asn_encode_length(length($_[4]) - $l - 2);
|
||||
}
|
||||
else {
|
||||
$_[4] .= asn_encode_length(length $_[3]);
|
||||
$_[4] .= $_[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my %_enc_time_opt = ( utctime => 1, withzone => 0, raw => 2);
|
||||
|
||||
sub _enc_time {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
my $mode = $_enc_time_opt{$_[0]->{'encode_time'} || ''} || 0;
|
||||
|
||||
if ($mode == 2) {
|
||||
$_[4] .= asn_encode_length(length $_[3]);
|
||||
$_[4] .= $_[3];
|
||||
return;
|
||||
}
|
||||
|
||||
my $time;
|
||||
my @time;
|
||||
my $offset;
|
||||
my $isgen = $_[1]->[cTYPE] == opGTIME;
|
||||
|
||||
if (ref($_[3])) {
|
||||
$offset = int($_[3]->[1] / 60);
|
||||
$time = $_[3]->[0] + $_[3]->[1];
|
||||
}
|
||||
elsif ($mode == 0) {
|
||||
if (exists $_[0]->{'encode_timezone'}) {
|
||||
$offset = int($_[0]->{'encode_timezone'} / 60);
|
||||
$time = $_[3] + $_[0]->{'encode_timezone'};
|
||||
}
|
||||
else {
|
||||
@time = localtime($_[3]);
|
||||
my @g = gmtime($_[3]);
|
||||
|
||||
$offset = ($time[1] - $g[1]) + ($time[2] - $g[2]) * 60;
|
||||
$time = $_[3] + $offset*60;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$time = $_[3];
|
||||
}
|
||||
@time = gmtime($time);
|
||||
$time[4] += 1;
|
||||
$time[5] = $isgen ? ($time[5] + 1900) : ($time[5] % 100);
|
||||
|
||||
my $tmp = sprintf("%02d"x6, @time[5,4,3,2,1,0]);
|
||||
if ($isgen) {
|
||||
my $sp = sprintf("%.03f",$time);
|
||||
$tmp .= substr($sp,-4) unless $sp =~ /\.000$/;
|
||||
}
|
||||
$tmp .= $offset ? sprintf("%+03d%02d",$offset / 60, abs($offset % 60)) : 'Z';
|
||||
$_[4] .= asn_encode_length(length $tmp);
|
||||
$_[4] .= $tmp;
|
||||
}
|
||||
|
||||
|
||||
sub _enc_utf8 {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
if (CHECK_UTF8) {
|
||||
my $tmp = $_[3];
|
||||
utf8::upgrade($tmp) unless Encode::is_utf8($tmp);
|
||||
utf8::encode($tmp);
|
||||
$_[4] .= asn_encode_length(length $tmp);
|
||||
$_[4] .= $tmp;
|
||||
}
|
||||
else {
|
||||
$_[4] .= asn_encode_length(length $_[3]);
|
||||
$_[4] .= $_[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _enc_any {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
my $handler;
|
||||
if ($_[1]->[cDEFINE] && $_[2]->{$_[1]->[cDEFINE]}) {
|
||||
$handler=$_[0]->{oidtable}{$_[2]->{$_[1]->[cDEFINE]}};
|
||||
$handler=$_[0]->{handlers}{$_[1]->[cVAR]}{$_[2]->{$_[1]->[cDEFINE]}} unless $handler;
|
||||
}
|
||||
if ($handler) {
|
||||
$_[4] .= $handler->encode($_[3]);
|
||||
} else {
|
||||
$_[4] .= $_[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _enc_choice {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
|
||||
my $stash = defined($_[3]) ? $_[3] : $_[2];
|
||||
for my $op (@{$_[1]->[cCHILD]}) {
|
||||
next if $op->[cTYPE] == opEXTENSIONS;
|
||||
my $var = defined $op->[cVAR] ? $op->[cVAR] : $op->[cCHILD]->[0]->[cVAR];
|
||||
|
||||
if (exists $stash->{$var}) {
|
||||
push @{$_[6]}, $var;
|
||||
_encode($_[0],[$op], $stash, $_[6], $_[4]);
|
||||
pop @{$_[6]};
|
||||
return;
|
||||
}
|
||||
}
|
||||
require Carp;
|
||||
Carp::croak("No value found for CHOICE " . join(".", @{$_[6]}));
|
||||
}
|
||||
|
||||
|
||||
sub _enc_bcd {
|
||||
# 0 1 2 3 4 5 6
|
||||
# $optn, $op, $stash, $var, $buf, $loop, $path
|
||||
my $str = ("$_[3]" =~ /^(\d+)/) ? $1 : "";
|
||||
$str .= "F" if length($str) & 1;
|
||||
$_[4] .= asn_encode_length(length($str) / 2);
|
||||
$_[4] .= pack("H*", $str);
|
||||
}
|
||||
1;
|
||||
|
||||
985
database/perl/vendor/lib/Convert/ASN1/parser.pm
vendored
Normal file
985
database/perl/vendor/lib/Convert/ASN1/parser.pm
vendored
Normal file
@@ -0,0 +1,985 @@
|
||||
#$yysccsid = "@(#)yaccpar 1.8 (Berkeley) 01/20/91 (Perl 2.0 12/31/92)";
|
||||
# 24 "parser.y"
|
||||
;# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
||||
;# This program is free software; you can redistribute it and/or
|
||||
;# modify it under the same terms as Perl itself.
|
||||
|
||||
package Convert::ASN1::parser;
|
||||
{
|
||||
$Convert::ASN1::parser::VERSION = '0.27';
|
||||
}
|
||||
|
||||
use strict;
|
||||
use Convert::ASN1 qw(:all);
|
||||
use vars qw(
|
||||
$asn $yychar $yyerrflag $yynerrs $yyn @yyss
|
||||
$yyssp $yystate @yyvs $yyvsp $yylval $yys $yym $yyval
|
||||
);
|
||||
|
||||
BEGIN { Convert::ASN1->_internal_syms }
|
||||
|
||||
my $yydebug=0;
|
||||
my %yystate;
|
||||
|
||||
my %base_type = (
|
||||
BOOLEAN => [ asn_encode_tag(ASN_BOOLEAN), opBOOLEAN ],
|
||||
INTEGER => [ asn_encode_tag(ASN_INTEGER), opINTEGER ],
|
||||
BIT_STRING => [ asn_encode_tag(ASN_BIT_STR), opBITSTR ],
|
||||
OCTET_STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
|
||||
STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
|
||||
NULL => [ asn_encode_tag(ASN_NULL), opNULL ],
|
||||
OBJECT_IDENTIFIER => [ asn_encode_tag(ASN_OBJECT_ID), opOBJID ],
|
||||
REAL => [ asn_encode_tag(ASN_REAL), opREAL ],
|
||||
ENUMERATED => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
|
||||
ENUM => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
|
||||
'RELATIVE-OID' => [ asn_encode_tag(ASN_RELATIVE_OID), opROID ],
|
||||
|
||||
SEQUENCE => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opSEQUENCE ],
|
||||
EXPLICIT => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opEXPLICIT ],
|
||||
SET => [ asn_encode_tag(ASN_SET | ASN_CONSTRUCTOR), opSET ],
|
||||
|
||||
ObjectDescriptor => [ asn_encode_tag(ASN_UNIVERSAL | 7), opSTRING ],
|
||||
UTF8String => [ asn_encode_tag(ASN_UNIVERSAL | 12), opUTF8 ],
|
||||
NumericString => [ asn_encode_tag(ASN_UNIVERSAL | 18), opSTRING ],
|
||||
PrintableString => [ asn_encode_tag(ASN_UNIVERSAL | 19), opSTRING ],
|
||||
TeletexString => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
|
||||
T61String => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
|
||||
VideotexString => [ asn_encode_tag(ASN_UNIVERSAL | 21), opSTRING ],
|
||||
IA5String => [ asn_encode_tag(ASN_UNIVERSAL | 22), opSTRING ],
|
||||
UTCTime => [ asn_encode_tag(ASN_UNIVERSAL | 23), opUTIME ],
|
||||
GeneralizedTime => [ asn_encode_tag(ASN_UNIVERSAL | 24), opGTIME ],
|
||||
GraphicString => [ asn_encode_tag(ASN_UNIVERSAL | 25), opSTRING ],
|
||||
VisibleString => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
|
||||
ISO646String => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
|
||||
GeneralString => [ asn_encode_tag(ASN_UNIVERSAL | 27), opSTRING ],
|
||||
CharacterString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
|
||||
UniversalString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
|
||||
BMPString => [ asn_encode_tag(ASN_UNIVERSAL | 30), opSTRING ],
|
||||
BCDString => [ asn_encode_tag(ASN_OCTET_STR), opBCD ],
|
||||
|
||||
CHOICE => [ '', opCHOICE ],
|
||||
ANY => [ '', opANY ],
|
||||
|
||||
EXTENSION_MARKER => [ '', opEXTENSIONS ],
|
||||
);
|
||||
|
||||
my $tagdefault = 1; # 0:IMPLICIT , 1:EXPLICIT default
|
||||
|
||||
;# args: class,plicit
|
||||
sub need_explicit {
|
||||
(defined($_[0]) && (defined($_[1])?$_[1]:$tagdefault));
|
||||
}
|
||||
|
||||
;# Given an OP, wrap it in a SEQUENCE
|
||||
|
||||
sub explicit {
|
||||
my $op = shift;
|
||||
my @seq = @$op;
|
||||
|
||||
@seq[cTYPE,cCHILD,cVAR,cLOOP] = ('EXPLICIT',[$op],undef,undef);
|
||||
@{$op}[cTAG,cOPT] = ();
|
||||
|
||||
\@seq;
|
||||
}
|
||||
|
||||
sub constWORD () { 1 }
|
||||
sub constCLASS () { 2 }
|
||||
sub constSEQUENCE () { 3 }
|
||||
sub constSET () { 4 }
|
||||
sub constCHOICE () { 5 }
|
||||
sub constOF () { 6 }
|
||||
sub constIMPLICIT () { 7 }
|
||||
sub constEXPLICIT () { 8 }
|
||||
sub constOPTIONAL () { 9 }
|
||||
sub constLBRACE () { 10 }
|
||||
sub constRBRACE () { 11 }
|
||||
sub constCOMMA () { 12 }
|
||||
sub constANY () { 13 }
|
||||
sub constASSIGN () { 14 }
|
||||
sub constNUMBER () { 15 }
|
||||
sub constENUM () { 16 }
|
||||
sub constCOMPONENTS () { 17 }
|
||||
sub constPOSTRBRACE () { 18 }
|
||||
sub constDEFINED () { 19 }
|
||||
sub constBY () { 20 }
|
||||
sub constEXTENSION_MARKER () { 21 }
|
||||
sub constYYERRCODE () { 256 }
|
||||
my @yylhs = ( -1,
|
||||
0, 0, 2, 2, 3, 3, 6, 6, 6, 6,
|
||||
8, 13, 13, 12, 14, 14, 14, 9, 9, 9,
|
||||
10, 18, 18, 18, 18, 18, 19, 19, 11, 16,
|
||||
16, 20, 20, 20, 21, 21, 1, 1, 1, 22,
|
||||
22, 22, 24, 24, 24, 24, 23, 23, 23, 23,
|
||||
15, 15, 4, 4, 5, 5, 5, 17, 17, 25,
|
||||
7, 7,
|
||||
);
|
||||
my @yylen = ( 2,
|
||||
1, 1, 3, 4, 4, 1, 1, 1, 1, 1,
|
||||
3, 1, 1, 6, 1, 1, 1, 4, 4, 4,
|
||||
4, 1, 1, 1, 2, 1, 0, 3, 1, 1,
|
||||
2, 1, 3, 3, 4, 1, 0, 1, 2, 1,
|
||||
3, 3, 2, 1, 1, 1, 4, 1, 3, 1,
|
||||
0, 1, 0, 1, 0, 1, 1, 1, 3, 2,
|
||||
0, 1,
|
||||
);
|
||||
my @yydefred = ( 0,
|
||||
0, 54, 0, 50, 0, 1, 0, 0, 48, 0,
|
||||
40, 0, 0, 0, 0, 57, 56, 0, 0, 0,
|
||||
3, 0, 6, 0, 11, 0, 0, 0, 0, 49,
|
||||
0, 41, 42, 0, 22, 0, 0, 0, 0, 46,
|
||||
44, 0, 45, 0, 29, 47, 4, 0, 0, 0,
|
||||
0, 7, 8, 9, 10, 0, 25, 0, 52, 43,
|
||||
0, 0, 0, 0, 36, 0, 0, 32, 62, 5,
|
||||
0, 0, 0, 58, 0, 18, 19, 0, 20, 0,
|
||||
0, 28, 60, 21, 0, 0, 0, 34, 33, 59,
|
||||
0, 0, 17, 15, 16, 0, 35, 14,
|
||||
);
|
||||
my @yydgoto = ( 5,
|
||||
6, 7, 21, 8, 18, 51, 70, 9, 52, 53,
|
||||
54, 55, 44, 96, 60, 66, 73, 45, 57, 67,
|
||||
68, 10, 11, 46, 74,
|
||||
);
|
||||
my @yysindex = ( 2,
|
||||
58, 0, 8, 0, 0, 0, 11, 123, 0, 3,
|
||||
0, 59, 123, 19, 73, 0, 0, 92, 7, 7,
|
||||
0, 123, 0, 119, 0, 59, 107, 109, 116, 0,
|
||||
82, 0, 0, 119, 0, 107, 109, 84, 126, 0,
|
||||
0, 90, 0, 132, 0, 0, 0, 7, 7, 10,
|
||||
139, 0, 0, 0, 0, 141, 0, 143, 0, 0,
|
||||
82, 156, 159, 82, 0, 160, 4, 0, 0, 0,
|
||||
171, 158, 6, 0, 123, 0, 0, 123, 0, 10,
|
||||
10, 0, 0, 0, 143, 124, 119, 0, 0, 0,
|
||||
107, 109, 0, 0, 0, 90, 0, 0,
|
||||
);
|
||||
my @yyrindex = ( 155,
|
||||
105, 0, 0, 0, 0, 0, 174, 111, 0, 80,
|
||||
0, 105, 138, 0, 0, 0, 0, 0, 161, 145,
|
||||
0, 138, 0, 0, 0, 105, 0, 0, 0, 0,
|
||||
105, 0, 0, 0, 0, 29, 33, 70, 74, 0,
|
||||
0, 46, 0, 0, 0, 0, 0, 45, 45, 0,
|
||||
54, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 0, 0, 105, 0, 0, 164, 0, 0, 0,
|
||||
0, 0, 0, 0, 138, 0, 0, 138, 0, 0,
|
||||
165, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
89, 93, 0, 0, 0, 25, 0, 0,
|
||||
);
|
||||
my @yygindex = ( 0,
|
||||
85, 0, 151, 1, -12, 91, 0, 47, -18, -19,
|
||||
-17, 157, 0, 0, 83, 0, 0, 0, 0, 0,
|
||||
-3, 0, 127, 0, 95,
|
||||
);
|
||||
sub constYYTABLESIZE () { 181 }
|
||||
my @yytable = ( 30,
|
||||
24, 13, 1, 2, 41, 40, 42, 31, 2, 34,
|
||||
64, 15, 22, 14, 19, 80, 84, 85, 3, 25,
|
||||
20, 81, 4, 3, 51, 51, 22, 4, 23, 23,
|
||||
65, 13, 24, 24, 12, 51, 51, 23, 13, 23,
|
||||
23, 24, 51, 24, 24, 51, 23, 53, 53, 53,
|
||||
24, 53, 53, 61, 61, 37, 51, 51, 23, 2,
|
||||
2, 75, 86, 51, 78, 87, 94, 93, 95, 27,
|
||||
27, 12, 23, 26, 26, 3, 88, 89, 27, 38,
|
||||
27, 27, 26, 2, 26, 26, 26, 27, 23, 23,
|
||||
38, 26, 24, 24, 27, 28, 29, 23, 59, 23,
|
||||
23, 24, 56, 24, 24, 53, 23, 53, 53, 53,
|
||||
24, 53, 53, 55, 55, 55, 48, 53, 49, 35,
|
||||
53, 36, 37, 29, 35, 50, 91, 92, 29, 16,
|
||||
17, 38, 62, 63, 39, 58, 38, 61, 55, 39,
|
||||
55, 55, 55, 72, 39, 32, 33, 53, 53, 53,
|
||||
55, 53, 53, 55, 37, 39, 69, 53, 53, 53,
|
||||
71, 53, 53, 53, 53, 53, 76, 53, 53, 77,
|
||||
79, 82, 83, 2, 30, 31, 47, 97, 98, 90,
|
||||
43,
|
||||
);
|
||||
my @yycheck = ( 18,
|
||||
13, 1, 1, 2, 24, 24, 24, 1, 2, 22,
|
||||
1, 1, 12, 6, 12, 12, 11, 12, 17, 1,
|
||||
18, 18, 21, 17, 0, 1, 26, 21, 0, 1,
|
||||
21, 31, 0, 1, 6, 11, 12, 9, 6, 11,
|
||||
12, 9, 18, 11, 12, 0, 18, 3, 4, 5,
|
||||
18, 7, 8, 0, 1, 11, 11, 12, 12, 2,
|
||||
2, 61, 75, 18, 64, 78, 86, 86, 86, 0,
|
||||
1, 14, 26, 0, 1, 17, 80, 81, 9, 0,
|
||||
11, 12, 9, 2, 11, 12, 14, 18, 0, 1,
|
||||
11, 18, 0, 1, 3, 4, 5, 9, 9, 11,
|
||||
12, 9, 19, 11, 12, 1, 18, 3, 4, 5,
|
||||
18, 7, 8, 3, 4, 5, 10, 13, 10, 1,
|
||||
16, 3, 4, 5, 1, 10, 3, 4, 5, 7,
|
||||
8, 13, 48, 49, 16, 10, 13, 6, 1, 16,
|
||||
3, 4, 5, 1, 0, 19, 20, 3, 4, 5,
|
||||
13, 7, 8, 16, 0, 11, 18, 3, 4, 5,
|
||||
20, 7, 8, 3, 4, 5, 11, 7, 8, 11,
|
||||
11, 1, 15, 0, 11, 11, 26, 87, 96, 85,
|
||||
24,
|
||||
);
|
||||
sub constYYFINAL () { 5 }
|
||||
|
||||
|
||||
|
||||
sub constYYMAXTOKEN () { 21 }
|
||||
sub yyclearin { $yychar = -1; }
|
||||
sub yyerrok { $yyerrflag = 0; }
|
||||
sub YYERROR { ++$yynerrs; &yy_err_recover; }
|
||||
sub yy_err_recover
|
||||
{
|
||||
if ($yyerrflag < 3)
|
||||
{
|
||||
$yyerrflag = 3;
|
||||
while (1)
|
||||
{
|
||||
if (($yyn = $yysindex[$yyss[$yyssp]]) &&
|
||||
($yyn += constYYERRCODE()) >= 0 &&
|
||||
$yyn <= $#yycheck && $yycheck[$yyn] == constYYERRCODE())
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
$yyss[++$yyssp] = $yystate = $yytable[$yyn];
|
||||
$yyvs[++$yyvsp] = $yylval;
|
||||
next yyloop;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
return(1) if $yyssp <= 0;
|
||||
--$yyssp;
|
||||
--$yyvsp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1) if $yychar == 0;
|
||||
$yychar = -1;
|
||||
next yyloop;
|
||||
}
|
||||
0;
|
||||
} # yy_err_recover
|
||||
|
||||
sub yyparse
|
||||
{
|
||||
|
||||
if ($yys = $ENV{'YYDEBUG'})
|
||||
{
|
||||
$yydebug = int($1) if $yys =~ /^(\d)/;
|
||||
}
|
||||
|
||||
|
||||
$yynerrs = 0;
|
||||
$yyerrflag = 0;
|
||||
$yychar = (-1);
|
||||
|
||||
$yyssp = 0;
|
||||
$yyvsp = 0;
|
||||
$yyss[$yyssp] = $yystate = 0;
|
||||
|
||||
yyloop: while(1)
|
||||
{
|
||||
yyreduce: {
|
||||
last yyreduce if ($yyn = $yydefred[$yystate]);
|
||||
if ($yychar < 0)
|
||||
{
|
||||
if (($yychar = &yylex) < 0) { $yychar = 0; }
|
||||
}
|
||||
if (($yyn = $yysindex[$yystate]) && ($yyn += $yychar) >= 0 &&
|
||||
$yyn <= $#yycheck && $yycheck[$yyn] == $yychar)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
$yyss[++$yyssp] = $yystate = $yytable[$yyn];
|
||||
$yyvs[++$yyvsp] = $yylval;
|
||||
$yychar = (-1);
|
||||
--$yyerrflag if $yyerrflag > 0;
|
||||
next yyloop;
|
||||
}
|
||||
if (($yyn = $yyrindex[$yystate]) && ($yyn += $yychar) >= 0 &&
|
||||
$yyn <= $#yycheck && $yycheck[$yyn] == $yychar)
|
||||
{
|
||||
$yyn = $yytable[$yyn];
|
||||
last yyreduce;
|
||||
}
|
||||
if (! $yyerrflag) {
|
||||
&yyerror('syntax error');
|
||||
++$yynerrs;
|
||||
}
|
||||
return undef if &yy_err_recover;
|
||||
} # yyreduce
|
||||
|
||||
|
||||
|
||||
|
||||
$yym = $yylen[$yyn];
|
||||
$yyval = $yyvs[$yyvsp+1-$yym];
|
||||
switch:
|
||||
{
|
||||
my $label = "State$yyn";
|
||||
goto $label if exists $yystate{$label};
|
||||
last switch;
|
||||
State1: {
|
||||
# 107 "parser.y"
|
||||
{ $yyval = { '' => $yyvs[$yyvsp-0] };
|
||||
last switch;
|
||||
} }
|
||||
State3: {
|
||||
# 112 "parser.y"
|
||||
{
|
||||
$yyval = { $yyvs[$yyvsp-2], [$yyvs[$yyvsp-0]] };
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State4: {
|
||||
# 116 "parser.y"
|
||||
{
|
||||
$yyval=$yyvs[$yyvsp-3];
|
||||
$yyval->{$yyvs[$yyvsp-2]} = [$yyvs[$yyvsp-0]];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State5: {
|
||||
# 123 "parser.y"
|
||||
{
|
||||
$yyvs[$yyvsp-1]->[cTAG] = $yyvs[$yyvsp-3];
|
||||
$yyval = need_explicit($yyvs[$yyvsp-3],$yyvs[$yyvsp-2]) ? explicit($yyvs[$yyvsp-1]) : $yyvs[$yyvsp-1];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State11: {
|
||||
# 137 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE,cCHILD] = ('COMPONENTS', $yyvs[$yyvsp-0]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State14: {
|
||||
# 147 "parser.y"
|
||||
{
|
||||
$yyvs[$yyvsp-1]->[cTAG] = $yyvs[$yyvsp-3];
|
||||
@{$yyval = []}[cTYPE,cCHILD,cLOOP,cOPT] = ($yyvs[$yyvsp-5], [$yyvs[$yyvsp-1]], 1, $yyvs[$yyvsp-0]);
|
||||
$yyval = explicit($yyval) if need_explicit($yyvs[$yyvsp-3],$yyvs[$yyvsp-2]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State18: {
|
||||
# 160 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE,cCHILD] = ('SEQUENCE', $yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State19: {
|
||||
# 164 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE,cCHILD] = ('SET', $yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State20: {
|
||||
# 168 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE,cCHILD] = ('CHOICE', $yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State21: {
|
||||
# 174 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE] = ('ENUM');
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State22: {
|
||||
# 179 "parser.y"
|
||||
{ @{$yyval = []}[cTYPE] = $yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State23: {
|
||||
# 180 "parser.y"
|
||||
{ @{$yyval = []}[cTYPE] = $yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State24: {
|
||||
# 181 "parser.y"
|
||||
{ @{$yyval = []}[cTYPE] = $yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State25: {
|
||||
# 183 "parser.y"
|
||||
{
|
||||
@{$yyval = []}[cTYPE,cCHILD,cDEFINE] = ('ANY',undef,$yyvs[$yyvsp-0]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State26: {
|
||||
# 186 "parser.y"
|
||||
{ @{$yyval = []}[cTYPE] = $yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State27: {
|
||||
# 189 "parser.y"
|
||||
{ $yyval=undef;
|
||||
last switch;
|
||||
} }
|
||||
State28: {
|
||||
# 190 "parser.y"
|
||||
{ $yyval=$yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State30: {
|
||||
# 196 "parser.y"
|
||||
{ $yyval = $yyvs[$yyvsp-0];
|
||||
last switch;
|
||||
} }
|
||||
State31: {
|
||||
# 197 "parser.y"
|
||||
{ $yyval = $yyvs[$yyvsp-1];
|
||||
last switch;
|
||||
} }
|
||||
State32: {
|
||||
# 201 "parser.y"
|
||||
{
|
||||
$yyval = [ $yyvs[$yyvsp-0] ];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State33: {
|
||||
# 205 "parser.y"
|
||||
{
|
||||
push @{$yyval=$yyvs[$yyvsp-2]}, $yyvs[$yyvsp-0];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State34: {
|
||||
# 209 "parser.y"
|
||||
{
|
||||
push @{$yyval=$yyvs[$yyvsp-2]}, $yyvs[$yyvsp-0];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State35: {
|
||||
# 215 "parser.y"
|
||||
{
|
||||
@{$yyval=$yyvs[$yyvsp-0]}[cVAR,cTAG] = ($yyvs[$yyvsp-3],$yyvs[$yyvsp-2]);
|
||||
$yyval = explicit($yyval) if need_explicit($yyvs[$yyvsp-2],$yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State36: {
|
||||
# 220 "parser.y"
|
||||
{
|
||||
@{$yyval=[]}[cTYPE] = 'EXTENSION_MARKER';
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State37: {
|
||||
# 226 "parser.y"
|
||||
{ $yyval = [];
|
||||
last switch;
|
||||
} }
|
||||
State38: {
|
||||
# 228 "parser.y"
|
||||
{
|
||||
my $extension = 0;
|
||||
$yyval = [];
|
||||
for my $i (@{$yyvs[$yyvsp-0]}) {
|
||||
$extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
|
||||
$i->[cEXT] = $i->[cOPT];
|
||||
$i->[cEXT] = 1 if $extension;
|
||||
push @{$yyval}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
|
||||
}
|
||||
my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
|
||||
push @{$yyval}, $e if $extension;
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State39: {
|
||||
# 241 "parser.y"
|
||||
{
|
||||
my $extension = 0;
|
||||
$yyval = [];
|
||||
for my $i (@{$yyvs[$yyvsp-1]}) {
|
||||
$extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
|
||||
$i->[cEXT] = $i->[cOPT];
|
||||
$i->[cEXT] = 1 if $extension;
|
||||
push @{$yyval}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
|
||||
}
|
||||
my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
|
||||
push @{$yyval}, $e if $extension;
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State40: {
|
||||
# 256 "parser.y"
|
||||
{
|
||||
$yyval = [ $yyvs[$yyvsp-0] ];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State41: {
|
||||
# 260 "parser.y"
|
||||
{
|
||||
push @{$yyval=$yyvs[$yyvsp-2]}, $yyvs[$yyvsp-0];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State42: {
|
||||
# 264 "parser.y"
|
||||
{
|
||||
push @{$yyval=$yyvs[$yyvsp-2]}, $yyvs[$yyvsp-0];
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State43: {
|
||||
# 270 "parser.y"
|
||||
{
|
||||
@{$yyval=$yyvs[$yyvsp-1]}[cOPT] = ($yyvs[$yyvsp-0]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State47: {
|
||||
# 279 "parser.y"
|
||||
{
|
||||
@{$yyval=$yyvs[$yyvsp-0]}[cVAR,cTAG] = ($yyvs[$yyvsp-3],$yyvs[$yyvsp-2]);
|
||||
$yyval->[cOPT] = $yyvs[$yyvsp-3] if $yyval->[cOPT];
|
||||
$yyval = explicit($yyval) if need_explicit($yyvs[$yyvsp-2],$yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State49: {
|
||||
# 286 "parser.y"
|
||||
{
|
||||
@{$yyval=$yyvs[$yyvsp-0]}[cTAG] = ($yyvs[$yyvsp-2]);
|
||||
$yyval = explicit($yyval) if need_explicit($yyvs[$yyvsp-2],$yyvs[$yyvsp-1]);
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State50: {
|
||||
# 291 "parser.y"
|
||||
{
|
||||
@{$yyval=[]}[cTYPE] = 'EXTENSION_MARKER';
|
||||
|
||||
last switch;
|
||||
} }
|
||||
State51: {
|
||||
# 296 "parser.y"
|
||||
{ $yyval = undef;
|
||||
last switch;
|
||||
} }
|
||||
State52: {
|
||||
# 297 "parser.y"
|
||||
{ $yyval = 1;
|
||||
last switch;
|
||||
} }
|
||||
State53: {
|
||||
# 301 "parser.y"
|
||||
{ $yyval = undef;
|
||||
last switch;
|
||||
} }
|
||||
State55: {
|
||||
# 305 "parser.y"
|
||||
{ $yyval = undef;
|
||||
last switch;
|
||||
} }
|
||||
State56: {
|
||||
# 306 "parser.y"
|
||||
{ $yyval = 1;
|
||||
last switch;
|
||||
} }
|
||||
State57: {
|
||||
# 307 "parser.y"
|
||||
{ $yyval = 0;
|
||||
last switch;
|
||||
} }
|
||||
State58: {
|
||||
# 310 "parser.y"
|
||||
{
|
||||
last switch;
|
||||
} }
|
||||
State59: {
|
||||
# 311 "parser.y"
|
||||
{
|
||||
last switch;
|
||||
} }
|
||||
State60: {
|
||||
# 314 "parser.y"
|
||||
{
|
||||
last switch;
|
||||
} }
|
||||
State61: {
|
||||
# 317 "parser.y"
|
||||
{
|
||||
last switch;
|
||||
} }
|
||||
State62: {
|
||||
# 318 "parser.y"
|
||||
{
|
||||
last switch;
|
||||
} }
|
||||
} # switch
|
||||
$yyssp -= $yym;
|
||||
$yystate = $yyss[$yyssp];
|
||||
$yyvsp -= $yym;
|
||||
$yym = $yylhs[$yyn];
|
||||
if ($yystate == 0 && $yym == 0)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
$yystate = constYYFINAL();
|
||||
$yyss[++$yyssp] = constYYFINAL();
|
||||
$yyvs[++$yyvsp] = $yyval;
|
||||
if ($yychar < 0)
|
||||
{
|
||||
if (($yychar = &yylex) < 0) { $yychar = 0; }
|
||||
}
|
||||
return $yyvs[$yyvsp] if $yychar == 0;
|
||||
next yyloop;
|
||||
}
|
||||
if (($yyn = $yygindex[$yym]) && ($yyn += $yystate) >= 0 &&
|
||||
$yyn <= $#yycheck && $yycheck[$yyn] == $yystate)
|
||||
{
|
||||
$yystate = $yytable[$yyn];
|
||||
} else {
|
||||
$yystate = $yydgoto[$yym];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$yyss[++$yyssp] = $yystate;
|
||||
$yyvs[++$yyvsp] = $yyval;
|
||||
} # yyloop
|
||||
} # yyparse
|
||||
# 322 "parser.y"
|
||||
|
||||
my %reserved = (
|
||||
'OPTIONAL' => constOPTIONAL(),
|
||||
'CHOICE' => constCHOICE(),
|
||||
'OF' => constOF(),
|
||||
'IMPLICIT' => constIMPLICIT(),
|
||||
'EXPLICIT' => constEXPLICIT(),
|
||||
'SEQUENCE' => constSEQUENCE(),
|
||||
'SET' => constSET(),
|
||||
'ANY' => constANY(),
|
||||
'ENUM' => constENUM(),
|
||||
'ENUMERATED' => constENUM(),
|
||||
'COMPONENTS' => constCOMPONENTS(),
|
||||
'{' => constLBRACE(),
|
||||
'}' => constRBRACE(),
|
||||
',' => constCOMMA(),
|
||||
'::=' => constASSIGN(),
|
||||
'DEFINED' => constDEFINED(),
|
||||
'BY' => constBY()
|
||||
);
|
||||
|
||||
my $reserved = join("|", reverse sort grep { /\w/ } keys %reserved);
|
||||
|
||||
my %tag_class = (
|
||||
APPLICATION => ASN_APPLICATION,
|
||||
UNIVERSAL => ASN_UNIVERSAL,
|
||||
PRIVATE => ASN_PRIVATE,
|
||||
CONTEXT => ASN_CONTEXT,
|
||||
'' => ASN_CONTEXT # if not specified, its CONTEXT
|
||||
);
|
||||
|
||||
;##
|
||||
;## This is NOT thread safe !!!!!!
|
||||
;##
|
||||
|
||||
my $pos;
|
||||
my $last_pos;
|
||||
my @stacked;
|
||||
|
||||
sub parse {
|
||||
local(*asn) = \($_[0]);
|
||||
$tagdefault = $_[1] eq 'EXPLICIT' ? 1 : 0;
|
||||
($pos,$last_pos,@stacked) = ();
|
||||
|
||||
eval {
|
||||
local $SIG{__DIE__};
|
||||
compile(verify(yyparse()));
|
||||
}
|
||||
}
|
||||
|
||||
sub compile_one {
|
||||
my $tree = shift;
|
||||
my $ops = shift;
|
||||
my $name = shift;
|
||||
foreach my $op (@$ops) {
|
||||
next unless ref($op) eq 'ARRAY';
|
||||
bless $op;
|
||||
my $type = $op->[cTYPE];
|
||||
if (exists $base_type{$type}) {
|
||||
$op->[cTYPE] = $base_type{$type}->[1];
|
||||
$op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $base_type{$type}->[0];
|
||||
}
|
||||
else {
|
||||
die "Unknown type '$type'\n" unless exists $tree->{$type};
|
||||
my $ref = compile_one(
|
||||
$tree,
|
||||
$tree->{$type},
|
||||
defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name
|
||||
);
|
||||
if (defined($op->[cTAG]) && $ref->[0][cTYPE] == opCHOICE) {
|
||||
@{$op}[cTYPE,cCHILD] = (opSEQUENCE,$ref);
|
||||
}
|
||||
else {
|
||||
@{$op}[cTYPE,cCHILD,cLOOP] = @{$ref->[0]}[cTYPE,cCHILD,cLOOP];
|
||||
}
|
||||
$op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $ref->[0][cTAG];
|
||||
}
|
||||
$op->[cTAG] |= pack("C",ASN_CONSTRUCTOR)
|
||||
if length $op->[cTAG] && ($op->[cTYPE] == opSET || $op->[cTYPE] == opEXPLICIT || $op->[cTYPE] == opSEQUENCE);
|
||||
|
||||
if ($op->[cCHILD]) {
|
||||
;# If we have children we are one of
|
||||
;# opSET opSEQUENCE opCHOICE opEXPLICIT
|
||||
|
||||
compile_one($tree, $op->[cCHILD], defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name);
|
||||
|
||||
;# If a CHOICE is given a tag, then it must be EXPLICIT
|
||||
if ($op->[cTYPE] == opCHOICE && defined($op->[cTAG]) && length($op->[cTAG])) {
|
||||
$op = bless explicit($op);
|
||||
$op->[cTYPE] = opSEQUENCE;
|
||||
}
|
||||
|
||||
if ( @{$op->[cCHILD]} > 1) {
|
||||
;#if ($op->[cTYPE] != opSEQUENCE) {
|
||||
;# Here we need to flatten CHOICEs and check that SET and CHOICE
|
||||
;# do not contain duplicate tags
|
||||
;#}
|
||||
if ($op->[cTYPE] == opSET) {
|
||||
;# In case we do CER encoding we order the SET elements by thier tags
|
||||
my @tags = map {
|
||||
length($_->[cTAG])
|
||||
? $_->[cTAG]
|
||||
: $_->[cTYPE] == opCHOICE
|
||||
? (sort map { $_->[cTAG] } $_->[cCHILD])[0]
|
||||
: ''
|
||||
} @{$op->[cCHILD]};
|
||||
@{$op->[cCHILD]} = @{$op->[cCHILD]}[sort { $tags[$a] cmp $tags[$b] } 0..$#tags];
|
||||
}
|
||||
}
|
||||
else {
|
||||
;# A SET of one element can be treated the same as a SEQUENCE
|
||||
$op->[cTYPE] = opSEQUENCE if $op->[cTYPE] == opSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
$ops;
|
||||
}
|
||||
|
||||
sub compile {
|
||||
my $tree = shift;
|
||||
|
||||
;# The tree should be valid enough to be able to
|
||||
;# - resolve references
|
||||
;# - encode tags
|
||||
;# - verify CHOICEs do not contain duplicate tags
|
||||
|
||||
;# once references have been resolved, and also due to
|
||||
;# flattening of COMPONENTS, it is possible for an op
|
||||
;# to appear in multiple places. So once an op is
|
||||
;# compiled we bless it. This ensure we dont try to
|
||||
;# compile it again.
|
||||
|
||||
while(my($k,$v) = each %$tree) {
|
||||
compile_one($tree,$v,$k);
|
||||
}
|
||||
|
||||
$tree;
|
||||
}
|
||||
|
||||
sub verify {
|
||||
my $tree = shift or return;
|
||||
my $err = "";
|
||||
|
||||
;# Well it parsed correctly, now we
|
||||
;# - check references exist
|
||||
;# - flatten COMPONENTS OF (checking for loops)
|
||||
;# - check for duplicate var names
|
||||
|
||||
while(my($name,$ops) = each %$tree) {
|
||||
my $stash = {};
|
||||
my @scope = ();
|
||||
my $path = "";
|
||||
my $idx = 0;
|
||||
|
||||
while($ops) {
|
||||
if ($idx < @$ops) {
|
||||
my $op = $ops->[$idx++];
|
||||
my $var;
|
||||
if (defined ($var = $op->[cVAR])) {
|
||||
|
||||
$err .= "$name: $path.$var used multiple times\n"
|
||||
if $stash->{$var}++;
|
||||
|
||||
}
|
||||
if (defined $op->[cCHILD]) {
|
||||
if (ref $op->[cCHILD]) {
|
||||
push @scope, [$stash, $path, $ops, $idx];
|
||||
if (defined $var) {
|
||||
$stash = {};
|
||||
$path .= "." . $var;
|
||||
}
|
||||
$idx = 0;
|
||||
$ops = $op->[cCHILD];
|
||||
}
|
||||
elsif ($op->[cTYPE] eq 'COMPONENTS') {
|
||||
splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD]));
|
||||
}
|
||||
else {
|
||||
die "Internal error\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $s = pop @scope
|
||||
or last;
|
||||
($stash,$path,$ops,$idx) = @$s;
|
||||
}
|
||||
}
|
||||
}
|
||||
die $err if length $err;
|
||||
$tree;
|
||||
}
|
||||
|
||||
sub expand_ops {
|
||||
my $tree = shift;
|
||||
my $want = shift;
|
||||
my $seen = shift || { };
|
||||
|
||||
die "COMPONENTS OF loop $want\n" if $seen->{$want}++;
|
||||
die "Undefined macro $want\n" unless exists $tree->{$want};
|
||||
my $ops = $tree->{$want};
|
||||
die "Bad macro for COMPUNENTS OF '$want'\n"
|
||||
unless @$ops == 1
|
||||
&& ($ops->[0][cTYPE] eq 'SEQUENCE' || $ops->[0][cTYPE] eq 'SET')
|
||||
&& ref $ops->[0][cCHILD];
|
||||
$ops = $ops->[0][cCHILD];
|
||||
for(my $idx = 0 ; $idx < @$ops ; ) {
|
||||
my $op = $ops->[$idx++];
|
||||
if ($op->[cTYPE] eq 'COMPONENTS') {
|
||||
splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD], $seen));
|
||||
}
|
||||
}
|
||||
|
||||
@$ops;
|
||||
}
|
||||
|
||||
sub _yylex {
|
||||
my $ret = &_yylex;
|
||||
warn $ret;
|
||||
$ret;
|
||||
}
|
||||
|
||||
sub yylex {
|
||||
return shift @stacked if @stacked;
|
||||
|
||||
while ($asn =~ /\G(?:
|
||||
(\s+|--[^\n]*)
|
||||
|
|
||||
([,{}]|::=)
|
||||
|
|
||||
($reserved)\b
|
||||
|
|
||||
(
|
||||
(?:OCTET|BIT)\s+STRING
|
||||
|
|
||||
OBJECT\s+IDENTIFIER
|
||||
|
|
||||
RELATIVE-OID
|
||||
)\b
|
||||
|
|
||||
(\w+(?:-\w+)*)
|
||||
|
|
||||
\[\s*
|
||||
(
|
||||
(?:(?:APPLICATION|PRIVATE|UNIVERSAL|CONTEXT)\s+)?
|
||||
\d+
|
||||
)
|
||||
\s*\]
|
||||
|
|
||||
\((\d+)\)
|
||||
|
|
||||
(\.\.\.)
|
||||
)/sxgo
|
||||
) {
|
||||
|
||||
($last_pos,$pos) = ($pos,pos($asn));
|
||||
|
||||
next if defined $1; # comment or whitespace
|
||||
|
||||
if (defined $2 or defined $3) {
|
||||
my $ret = $+;
|
||||
|
||||
# A comma is not required after a '}' so to aid the
|
||||
# parser we insert a fake token after any '}'
|
||||
if ($ret eq '}') {
|
||||
my $p = pos($asn);
|
||||
my @tmp = @stacked;
|
||||
@stacked = ();
|
||||
pos($asn) = $p if yylex() != constCOMMA(); # swallow it
|
||||
@stacked = (@tmp, constPOSTRBRACE());
|
||||
}
|
||||
|
||||
return $reserved{$yylval = $ret};
|
||||
}
|
||||
|
||||
if (defined $4) {
|
||||
($yylval = $+) =~ s/\s+/_/g;
|
||||
return constWORD();
|
||||
}
|
||||
|
||||
if (defined $5) {
|
||||
$yylval = $+;
|
||||
return constWORD();
|
||||
}
|
||||
|
||||
if (defined $6) {
|
||||
my($class,$num) = ($+ =~ /^([A-Z]*)\s*(\d+)$/);
|
||||
$yylval = asn_tag($tag_class{$class}, $num);
|
||||
return constCLASS();
|
||||
}
|
||||
|
||||
if (defined $7) {
|
||||
$yylval = $+;
|
||||
return constNUMBER();
|
||||
}
|
||||
|
||||
if (defined $8) {
|
||||
return constEXTENSION_MARKER();
|
||||
}
|
||||
|
||||
die "Internal error\n";
|
||||
|
||||
}
|
||||
|
||||
die "Parse error before ",substr($asn,$pos,40),"\n"
|
||||
unless $pos == length($asn);
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
sub yyerror {
|
||||
die @_," ",substr($asn,$last_pos,40),"\n";
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
%yystate = ('State51','','State34','','State11','','State33','','State24',
|
||||
'','State47','','State40','','State31','','State37','','State23','',
|
||||
'State22','','State21','','State57','','State39','','State56','','State20',
|
||||
'','State25','','State38','','State62','','State14','','State19','',
|
||||
'State5','','State53','','State26','','State27','','State50','','State36',
|
||||
'','State4','','State3','','State32','','State49','','State43','','State30',
|
||||
'','State35','','State52','','State55','','State42','','State28','',
|
||||
'State58','','State61','','State41','','State18','','State59','','State1',
|
||||
'','State60','');
|
||||
|
||||
1;
|
||||
480
database/perl/vendor/lib/Convert/PEM.pm
vendored
Normal file
480
database/perl/vendor/lib/Convert/PEM.pm
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
package Convert::PEM;
|
||||
use strict;
|
||||
use 5.008_001;
|
||||
|
||||
use base qw( Class::ErrorHandler );
|
||||
|
||||
use MIME::Base64;
|
||||
use Digest::MD5 qw( md5 );
|
||||
use Convert::ASN1;
|
||||
use Carp qw( croak );
|
||||
use Convert::PEM::CBC;
|
||||
|
||||
use vars qw( $VERSION );
|
||||
$VERSION = '0.08';
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $pem = bless { }, $class;
|
||||
$pem->init(@_);
|
||||
}
|
||||
|
||||
sub init {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
unless (exists $param{ASN} && exists $param{Name}) {
|
||||
return (ref $pem)->error("init: Name and ASN are required");
|
||||
}
|
||||
else {
|
||||
$pem->{ASN} = $param{ASN};
|
||||
$pem->{Name} = $param{Name};
|
||||
}
|
||||
$pem->{Macro} = $param{Macro};
|
||||
my $asn = $pem->{_asn} = Convert::ASN1->new;
|
||||
$asn->prepare( $pem->{ASN} ) or
|
||||
return (ref $pem)->error("ASN prepare failed: $asn->{error}");
|
||||
$pem;
|
||||
}
|
||||
|
||||
sub asn { $_[0]->{_asn} }
|
||||
sub ASN { $_[0]->{ASN} }
|
||||
sub name { $_[0]->{Name} }
|
||||
|
||||
sub read {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
|
||||
my $blob;
|
||||
local *FH;
|
||||
my $fname = delete $param{Filename};
|
||||
open FH, $fname or
|
||||
return $pem->error("Can't open $fname: $!");
|
||||
$blob = do { local $/; <FH> };
|
||||
close FH;
|
||||
|
||||
$param{Content} = $blob;
|
||||
$pem->decode(%param);
|
||||
}
|
||||
|
||||
sub write {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
|
||||
my $fname = delete $param{Filename} or
|
||||
return $pem->error("write: Filename is required");
|
||||
my $blob = $pem->encode(%param);
|
||||
|
||||
local *FH;
|
||||
open FH, ">$fname" or
|
||||
return $pem->error("Can't open $fname: $!");
|
||||
print FH $blob;
|
||||
close FH;
|
||||
$blob;
|
||||
}
|
||||
|
||||
sub decode {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
my $blob = $param{Content} or
|
||||
return $pem->error("'Content' is required");
|
||||
chomp $blob;
|
||||
|
||||
my $dec = $pem->explode($blob) or return;
|
||||
my $name = $param{Name} || $pem->name;
|
||||
return $pem->error("Object $dec->{Object} does not match " . $name)
|
||||
unless $dec->{Object} eq $name;
|
||||
|
||||
my $head = $dec->{Headers};
|
||||
my $buf = $dec->{Content};
|
||||
my %headers = map { $_->[0] => $_->[1] } @$head;
|
||||
if (%headers && $headers{'Proc-Type'} eq '4,ENCRYPTED') {
|
||||
$buf = $pem->decrypt( Ciphertext => $buf,
|
||||
Info => $headers{'DEK-Info'},
|
||||
Password => $param{Password} )
|
||||
or return;
|
||||
}
|
||||
|
||||
my $asn = $pem->asn;
|
||||
if (my $macro = ($param{Macro} || $pem->{Macro})) {
|
||||
$asn = $asn->find($macro) or
|
||||
return $pem->error("Can't find Macro $macro");
|
||||
}
|
||||
my $obj = $asn->decode($buf) or
|
||||
return $pem->error("ASN decode failed: $asn->{error}");
|
||||
|
||||
$obj;
|
||||
}
|
||||
|
||||
sub encode {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
|
||||
my $asn = $pem->asn;
|
||||
if (my $macro = ($param{Macro} || $pem->{Macro})) {
|
||||
$asn = $asn->find($macro) or
|
||||
return $pem->error("Can't find Macro $macro");
|
||||
}
|
||||
my $buf = $asn->encode( $param{Content} ) or
|
||||
return $pem->error("ASN encode failed: $asn->{error}");
|
||||
|
||||
my(@headers);
|
||||
if ($param{Password}) {
|
||||
my($info);
|
||||
($buf, $info) = $pem->encrypt( Plaintext => $buf,
|
||||
Password => $param{Password} )
|
||||
or return;
|
||||
push @headers, [ 'Proc-Type' => '4,ENCRYPTED' ];
|
||||
push @headers, [ 'DEK-Info' => $info ];
|
||||
}
|
||||
|
||||
$pem->implode( Object => $param{Name} || $pem->name,
|
||||
Headers => \@headers,
|
||||
Content => $buf );
|
||||
}
|
||||
|
||||
sub explode {
|
||||
my $pem = shift;
|
||||
my($message) = @_;
|
||||
|
||||
# Canonicalize line endings into "\n".
|
||||
$message =~ s/\r\n|\n|\r/\n/g;
|
||||
|
||||
my($head, $object, $headers, $content, $tail) = $message =~
|
||||
m:(-----BEGIN ([^\n\-]+)-----)\n(.*?\n\n)?(.+)(-----END .*?-----)$:s;
|
||||
my $buf = decode_base64($content);
|
||||
|
||||
my @headers;
|
||||
if ($headers) {
|
||||
for my $h ( split /\n/, $headers ) {
|
||||
my($k, $v) = split /:\s*/, $h, 2;
|
||||
push @headers, [ $k => $v ] if $k;
|
||||
}
|
||||
}
|
||||
|
||||
{ Content => $buf,
|
||||
Object => $object,
|
||||
Headers => \@headers }
|
||||
}
|
||||
|
||||
sub implode {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
my $head = "-----BEGIN $param{Object}-----";
|
||||
my $tail = "-----END $param{Object}-----";
|
||||
my $content = encode_base64( $param{Content}, '' );
|
||||
$content =~ s!(.{1,64})!$1\n!g;
|
||||
my $headers = join '',
|
||||
map { "$_->[0]: $_->[1]\n" }
|
||||
@{ $param{Headers} };
|
||||
$headers .= "\n" if $headers;
|
||||
"$head\n$headers$content$tail\n";
|
||||
}
|
||||
|
||||
use vars qw( %CTYPES );
|
||||
%CTYPES = ('DES-EDE3-CBC' => 'Crypt::DES_EDE3');
|
||||
|
||||
sub decrypt {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
my $passphrase = $param{Password} || "";
|
||||
my($ctype, $iv) = split /,/, $param{Info};
|
||||
my $cmod = $CTYPES{$ctype} or
|
||||
return $pem->error("Unrecognized cipher: '$ctype'");
|
||||
$iv = pack "H*", $iv;
|
||||
my $cbc = Convert::PEM::CBC->new(
|
||||
Passphrase => $passphrase,
|
||||
Cipher => $cmod,
|
||||
IV => $iv );
|
||||
my $buf = $cbc->decrypt($param{Ciphertext}) or
|
||||
return $pem->error("Decryption failed: " . $cbc->errstr);
|
||||
$buf;
|
||||
}
|
||||
|
||||
sub encrypt {
|
||||
my $pem = shift;
|
||||
my %param = @_;
|
||||
$param{Password} or return $param{Plaintext};
|
||||
my $ctype = $param{Cipher} || 'DES-EDE3-CBC';
|
||||
my $cmod = $CTYPES{$ctype} or
|
||||
return $pem->error("Unrecognized cipher: '$ctype'");
|
||||
my $cbc = Convert::PEM::CBC->new(
|
||||
Passphrase => $param{Password},
|
||||
Cipher => $cmod );
|
||||
my $iv = uc join '', unpack "H*", $cbc->iv;
|
||||
my $buf = $cbc->encrypt($param{Plaintext}) or
|
||||
return $pem->error("Encryption failed: " . $cbc->errstr);
|
||||
($buf, "$ctype,$iv");
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Convert::PEM - Read/write encrypted ASN.1 PEM files
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Convert::PEM;
|
||||
my $pem = Convert::PEM->new(
|
||||
Name => "DSA PRIVATE KEY",
|
||||
ASN => qq(
|
||||
DSAPrivateKey SEQUENCE {
|
||||
version INTEGER,
|
||||
p INTEGER,
|
||||
q INTEGER,
|
||||
g INTEGER,
|
||||
pub_key INTEGER,
|
||||
priv_key INTEGER
|
||||
}
|
||||
));
|
||||
|
||||
my $keyfile = 'private-key.pem';
|
||||
my $pwd = 'foobar';
|
||||
|
||||
my $pkey = $pem->read(
|
||||
Filename => $keyfile,
|
||||
Password => $pwd
|
||||
);
|
||||
|
||||
$pem->write(
|
||||
Content => $pkey,
|
||||
Password => $pwd,
|
||||
Filename => $keyfile
|
||||
);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
I<Convert::PEM> reads and writes PEM files containing ASN.1-encoded
|
||||
objects. The files can optionally be encrypted using a symmetric
|
||||
cipher algorithm, such as 3DES. An unencrypted PEM file might look
|
||||
something like this:
|
||||
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MB4CGQDUoLoCULb9LsYm5+/WN992xxbiLQlEuIsCAQM=
|
||||
-----END DH PARAMETERS-----
|
||||
|
||||
The string beginning C<MB4C...> is the Base64-encoded, ASN.1-encoded
|
||||
"object."
|
||||
|
||||
An encrypted file would have headers describing the type of
|
||||
encryption used, and the initialization vector:
|
||||
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,C814158661DC1449
|
||||
|
||||
AFAZFbnQNrGjZJ/ZemdVSoZa3HWujxZuvBHzHNoesxeyqqidFvnydA==
|
||||
-----END DH PARAMETERS-----
|
||||
|
||||
The two headers (C<Proc-Type> and C<DEK-Info>) indicate information
|
||||
about the type of encryption used, and the string starting with
|
||||
C<AFAZ...> is the Base64-encoded, encrypted, ASN.1-encoded
|
||||
contents of this "object."
|
||||
|
||||
The initialization vector (C<C814158661DC1449>) is chosen randomly.
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
=head2 $pem = Convert::PEM->new( %arg )
|
||||
|
||||
Constructs a new I<Convert::PEM> object designed to read/write an
|
||||
object of a specific type (given in I<%arg>, see below). Returns the
|
||||
new object on success, C<undef> on failure (see I<ERROR HANDLING> for
|
||||
details).
|
||||
|
||||
I<%arg> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Name
|
||||
|
||||
The name of the object; when decoding a PEM-encoded stream, the name
|
||||
in the encoding will be checked against the value of I<Name>.
|
||||
Similarly, when encoding an object, the value of I<Name> will be used
|
||||
as the name of the object in the PEM-encoded content. For example, given
|
||||
the string C<FOO BAR>, the output from I<encode> will start with a
|
||||
header like:
|
||||
|
||||
-----BEGIN FOO BAR-----
|
||||
|
||||
I<Name> is a required argument.
|
||||
|
||||
=item * ASN
|
||||
|
||||
An ASN.1 description of the content to be either encoded or decoded.
|
||||
|
||||
I<ASN> is a required argument.
|
||||
|
||||
=item * Macro
|
||||
|
||||
If your ASN.1 description (in the I<ASN> parameter) includes more than
|
||||
one ASN.1 macro definition, you will want to use the I<Macro> parameter
|
||||
to specify which definition to use when encoding/decoding objects.
|
||||
For example, if your ASN.1 description looks like this:
|
||||
|
||||
Foo ::= SEQUENCE {
|
||||
x INTEGER,
|
||||
bar Bar
|
||||
}
|
||||
|
||||
Bar ::= INTEGER
|
||||
|
||||
If you want to encode/decode a C<Foo> object, you will need to tell
|
||||
I<Convert::PEM> to use the C<Foo> macro definition by using the I<Macro>
|
||||
parameter and setting the value to C<Foo>.
|
||||
|
||||
I<Macro> is an optional argument.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $obj = $pem->decode(%args)
|
||||
|
||||
Decodes, and, optionally, decrypts a PEM file, returning the
|
||||
object as decoded by I<Convert::ASN1>. The difference between this
|
||||
method and I<read> is that I<read> reads the contents of a PEM file
|
||||
on disk; this method expects you to pass the PEM contents as an
|
||||
argument.
|
||||
|
||||
If an error occurs while reading the file or decrypting/decoding
|
||||
the contents, the function returns I<undef>, and you should check
|
||||
the error message using the I<errstr> method (below).
|
||||
|
||||
I<%args> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Content
|
||||
|
||||
The PEM contents.
|
||||
|
||||
=item * Password
|
||||
|
||||
The password with which the file contents were encrypted.
|
||||
|
||||
If the file is encrypted, this is a mandatory argument (well, it's
|
||||
not strictly mandatory, but decryption isn't going to work without
|
||||
it). Otherwise it's not necessary.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $blob = $pem->encode(%args)
|
||||
|
||||
Constructs the contents for the PEM file from an object: ASN.1-encodes
|
||||
the object, optionally encrypts those contents.
|
||||
|
||||
Returns I<undef> on failure (encryption failure, file-writing failure,
|
||||
etc.); in this case you should check the error message using the
|
||||
I<errstr> method (below). On success returns the constructed PEM string.
|
||||
|
||||
I<%args> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Content
|
||||
|
||||
A hash reference that will be passed to I<Convert::ASN1::encode>,
|
||||
and which should correspond to the ASN.1 description you gave to the
|
||||
I<new> method. The hash reference should have the exact same format
|
||||
as that returned from the I<read> method.
|
||||
|
||||
This argument is mandatory.
|
||||
|
||||
=item * Password
|
||||
|
||||
A password used to encrypt the contents of the PEM file. This is an
|
||||
optional argument; if not provided the contents will be unencrypted.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $obj = $pem->read(%args)
|
||||
|
||||
Reads, decodes, and, optionally, decrypts a PEM file, returning
|
||||
the object as decoded by I<Convert::ASN1>. This is implemented
|
||||
as a wrapper around I<decode>, with the bonus of reading the PEM
|
||||
file from disk for you.
|
||||
|
||||
If an error occurs while reading the file or decrypting/decoding
|
||||
the contents, the function returns I<undef>, and you should check
|
||||
the error message using the I<errstr> method (below).
|
||||
|
||||
In addition to the arguments that can be passed to the I<decode>
|
||||
method (minus the I<Content> method), I<%args> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Filename
|
||||
|
||||
The location of the PEM file that you wish to read.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $pem->write(%args)
|
||||
|
||||
Constructs the contents for the PEM file from an object: ASN.1-encodes
|
||||
the object, optionally encrypts those contents; then writes the file
|
||||
to disk. This is implemented as a wrapper around I<encode>, with the
|
||||
bonus of writing the file to disk for you.
|
||||
|
||||
Returns I<undef> on failure (encryption failure, file-writing failure,
|
||||
etc.); in this case you should check the error message using the
|
||||
I<errstr> method (below). On success returns the constructed PEM string.
|
||||
|
||||
In addition to the arguments for I<encode>, I<%args> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Filename
|
||||
|
||||
The location on disk where you'd like the PEM file written.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $pem->errstr
|
||||
|
||||
Returns the value of the last error that occurred. This should only
|
||||
be considered meaningful when you've received I<undef> from one of
|
||||
the functions above; in all other cases its relevance is undefined.
|
||||
|
||||
=head2 $pem->asn
|
||||
|
||||
Returns the I<Convert::ASN1> object used internally to decode and
|
||||
encode ASN.1 representations. This is useful when you wish to
|
||||
interact directly with that object; for example, if you need to
|
||||
call I<configure> on that object to set the type of big-integer
|
||||
class to be used when decoding/encoding big integers:
|
||||
|
||||
$pem->asn->configure( decode => { bigint => 'Math::Pari' },
|
||||
encode => { bigint => 'Math::Pari' } );
|
||||
|
||||
=head1 ERROR HANDLING
|
||||
|
||||
If an error occurs in any of the above methods, the method will return
|
||||
C<undef>. You should then call the method I<errstr> to determine the
|
||||
source of the error:
|
||||
|
||||
$pem->errstr
|
||||
|
||||
In the case that you do not yet have a I<Convert::PEM> object (that is,
|
||||
if an error occurs while creating a I<Convert::PEM> object), the error
|
||||
can be obtained as a class method:
|
||||
|
||||
Convert::PEM->errstr
|
||||
|
||||
For example, if you try to decode an encrypted object, and you do not
|
||||
give a passphrase to decrypt the object:
|
||||
|
||||
my $obj = $pem->read( Filename => "encrypted.pem" )
|
||||
or die "Decryption failed: ", $pem->errstr;
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
Convert::PEM is free software; you may redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=head1 AUTHOR & COPYRIGHTS
|
||||
|
||||
Except where otherwise noted, Convert::PEM is Copyright Benjamin
|
||||
Trott, cpan@stupidfool.org. All rights reserved.
|
||||
|
||||
=cut
|
||||
226
database/perl/vendor/lib/Convert/PEM/CBC.pm
vendored
Normal file
226
database/perl/vendor/lib/Convert/PEM/CBC.pm
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
package Convert::PEM::CBC;
|
||||
use strict;
|
||||
|
||||
use Carp qw( croak );
|
||||
use Digest::MD5 qw( md5 );
|
||||
use base qw( Class::ErrorHandler );
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $cbc = bless { }, $class;
|
||||
$cbc->init(@_);
|
||||
}
|
||||
|
||||
sub init {
|
||||
my $cbc = shift;
|
||||
my %param = @_;
|
||||
$cbc->{iv} = exists $param{IV} ? $param{IV} :
|
||||
pack("C*", map { rand 255 } 1..8);
|
||||
croak "init: Cipher is required"
|
||||
unless my $cipher = $param{Cipher};
|
||||
if (ref($cipher)) {
|
||||
$cbc->{cipher} = $cipher;
|
||||
}
|
||||
else {
|
||||
eval "use $cipher;";
|
||||
croak "Loading '$cipher' failed: $@" if $@;
|
||||
my $key = $param{Key};
|
||||
if (!$key && exists $param{Passphrase}) {
|
||||
$key = bytes_to_key($param{Passphrase}, $cbc->{iv},
|
||||
\&md5, $cipher->keysize);
|
||||
}
|
||||
croak "init: either Key or Passphrase required"
|
||||
unless $key;
|
||||
$cbc->{cipher} = $cipher->new($key);
|
||||
}
|
||||
$cbc;
|
||||
}
|
||||
|
||||
sub iv { $_[0]->{iv} }
|
||||
|
||||
sub encrypt {
|
||||
my $cbc = shift;
|
||||
my($text) = @_;
|
||||
my $cipher = $cbc->{cipher};
|
||||
my $bs = $cipher->blocksize;
|
||||
my @blocks = $text =~ /(.{1,$bs})/ogs;
|
||||
my $last = pop @blocks if length($blocks[-1]) < $bs;
|
||||
my $iv = $cbc->{iv};
|
||||
my $buf = '';
|
||||
for my $block (@blocks) {
|
||||
$buf .= $iv = $cipher->encrypt($iv ^ $block);
|
||||
}
|
||||
$last = pack("C*", ($bs) x $bs) unless $last && length $last;
|
||||
if (length $last) {
|
||||
$last .= pack("C*", ($bs-length($last)) x ($bs-length($last)))
|
||||
if length($last) < $bs;
|
||||
$buf .= $iv = $cipher->encrypt($iv ^ $last);
|
||||
}
|
||||
$cbc->{iv} = $iv;
|
||||
$buf;
|
||||
}
|
||||
|
||||
sub decrypt {
|
||||
my $cbc = shift;
|
||||
my($text) = @_;
|
||||
my $cipher = $cbc->{cipher};
|
||||
my $bs = $cipher->blocksize;
|
||||
my @blocks = $text =~ /(.{1,$bs})/ogs;
|
||||
my $last = length($blocks[-1]) < $bs ?
|
||||
join '', splice(@blocks, -2) : pop @blocks;
|
||||
my $iv = $cbc->{iv};
|
||||
my $buf = '';
|
||||
for my $block (@blocks) {
|
||||
$buf .= $iv ^ $cipher->decrypt($block);
|
||||
$iv = $block;
|
||||
}
|
||||
$last = pack "a$bs", $last;
|
||||
if (length($last)) {
|
||||
my $tmp = $iv ^ $cipher->decrypt($last);
|
||||
$iv = $last;
|
||||
$last = $tmp;
|
||||
my $cut = ord substr $last, -1;
|
||||
return $cbc->error("Bad key/passphrase")
|
||||
if $cut > $bs;
|
||||
substr($last, -$cut) = '';
|
||||
$buf .= $last;
|
||||
}
|
||||
$cbc->{iv} = $iv;
|
||||
$buf;
|
||||
}
|
||||
|
||||
sub bytes_to_key {
|
||||
my($key, $salt, $md, $ks) = @_;
|
||||
my $ckey = $md->($key, $salt);
|
||||
while (length($ckey) < $ks) {
|
||||
$ckey .= $md->($ckey, $key, $salt);
|
||||
}
|
||||
substr $ckey, 0, $ks;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Convert::PEM::CBC - Cipher Block Chaining Mode implementation
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Convert::PEM::CBC;
|
||||
my $cbc = Convert::PEM::CBC->new(
|
||||
Cipher => 'Crypt::DES_EDE3',
|
||||
Passphrase => 'foo'
|
||||
);
|
||||
|
||||
my $plaintext = 'foo bar baz';
|
||||
$cbc->encrypt($plaintext);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
I<Convert::PEM::CBC> implements the CBC (Cipher Block Chaining)
|
||||
mode for encryption/decryption ciphers; the CBC is designed for
|
||||
compatability with OpenSSL and may not be compatible with other
|
||||
implementations (such as SSH).
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
=head2 $cbc = Convert::PEM::CBC->new(%args)
|
||||
|
||||
Creates a new I<Convert::PEM::CBC> object and initializes it.
|
||||
Returns the new object.
|
||||
|
||||
I<%args> can contain:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * Cipher
|
||||
|
||||
Either the name of an encryption cipher class (eg. I<Crypt::DES>),
|
||||
or an object already blessed into such a class. The class must
|
||||
support the I<keysize>, I<blocksize>, I<encrypt>, and I<decrypt>
|
||||
methods. If the value is a blessed object, it is assumed that the
|
||||
object has already been initialized with a key.
|
||||
|
||||
This argument is mandatory.
|
||||
|
||||
=item * Passphrase
|
||||
|
||||
A passphrase to encrypt/decrypt the content. This is different in
|
||||
implementation from a key (I<Key>), because it is assumed that a
|
||||
passphrase comes directly from a user, and must be munged into the
|
||||
correct form for a key. This "munging" is done by repeatedly
|
||||
computing an MD5 hash of the passphrase, the IV, and the existing
|
||||
hash, until the generated key is longer than the keysize for the
|
||||
cipher (I<Cipher>).
|
||||
|
||||
Because of this "munging", this argument can be any length (even
|
||||
an empty string).
|
||||
|
||||
If you give the I<Cipher> argument an object, this argument is
|
||||
ignored. If the I<Cipher> argument is a cipher class, either this
|
||||
argument or I<Key> must be provided.
|
||||
|
||||
=item * Key
|
||||
|
||||
A raw key, to be passed directly to the new cipher object. Because
|
||||
this is passed directly to the cipher itself, the length of the
|
||||
key must be equal to or greater than the keysize for the I<Cipher>.
|
||||
|
||||
As with the I<Passphrase> argument, if you give the I<Cipher>
|
||||
argument an already-constructed cipher object, this argument is
|
||||
ignored. If the I<Cipher> argument is a cipher class, either this
|
||||
argument or I<Passphrase> must be provided.
|
||||
|
||||
=item * IV
|
||||
|
||||
The initialization vector for CBC mode.
|
||||
|
||||
This argument is optional; if not provided, a random IV will be
|
||||
generated. Obviously, if you're decrypting data, you should provide
|
||||
this argument, because your IV should match the IV used to encrypt
|
||||
the data.
|
||||
|
||||
=back
|
||||
|
||||
=head2 $cbc->encrypt($plaintext)
|
||||
|
||||
Encrypts the plaintext I<$plaintext> using the underlying cipher
|
||||
implementation in CBC mode, and returns the ciphertext.
|
||||
|
||||
If any errors occur, returns I<undef>, and you should check the
|
||||
I<errstr> method to find out what went wrong.
|
||||
|
||||
=head2 $cbc->decrypt($ciphertext)
|
||||
|
||||
Decrypts the ciphertext I<$ciphertext> using the underlying
|
||||
cipher implementation in CBC mode, and returns the plaintext.
|
||||
|
||||
If any errors occur, returns I<undef>, and you should check the
|
||||
I<errstr> method to find out what went wrong.
|
||||
|
||||
=head2 $cbc->iv
|
||||
|
||||
Returns the current initialization vector. One use for this might be
|
||||
to grab the initial value of the IV if it's created randomly (ie.
|
||||
you haven't provided an I<IV> argument to I<new>):
|
||||
|
||||
my $cbc = Convert::PEM::CBC->new( Cipher => $cipher );
|
||||
my $iv = $cbc->iv; ## Generated randomly in 'new'.
|
||||
|
||||
I<Convert::PEM> uses this to write the IV to the PEM file when
|
||||
encrypting, so that it can be known when trying to decrypt the
|
||||
file.
|
||||
|
||||
=head2 $cbc->errstr
|
||||
|
||||
Returns the value of the last error that occurred. This should only
|
||||
be considered meaningful when you've received I<undef> from one of
|
||||
the functions above; in all other cases its relevance is undefined.
|
||||
|
||||
=head1 AUTHOR & COPYRIGHTS
|
||||
|
||||
Please see the Convert::PEM manpage for author, copyright, and
|
||||
license information.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user