|
Packit |
ef9df4 |
%token WORD 1
|
|
Packit |
ef9df4 |
%token CLASS 2
|
|
Packit |
ef9df4 |
%token SEQUENCE 3
|
|
Packit |
ef9df4 |
%token SET 4
|
|
Packit |
ef9df4 |
%token CHOICE 5
|
|
Packit |
ef9df4 |
%token OF 6
|
|
Packit |
ef9df4 |
%token IMPLICIT 7
|
|
Packit |
ef9df4 |
%token EXPLICIT 8
|
|
Packit |
ef9df4 |
%token OPTIONAL 9
|
|
Packit |
ef9df4 |
%token LBRACE 10
|
|
Packit |
ef9df4 |
%token RBRACE 11
|
|
Packit |
ef9df4 |
%token COMMA 12
|
|
Packit |
ef9df4 |
%token ANY 13
|
|
Packit |
ef9df4 |
%token ASSIGN 14
|
|
Packit |
ef9df4 |
%token NUMBER 15
|
|
Packit |
ef9df4 |
%token ENUM 16
|
|
Packit |
ef9df4 |
%token COMPONENTS 17
|
|
Packit |
ef9df4 |
%token POSTRBRACE 18
|
|
Packit |
ef9df4 |
%token DEFINED 19
|
|
Packit |
ef9df4 |
%token BY 20
|
|
Packit |
ef9df4 |
%token EXTENSION_MARKER 21
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
%{
|
|
Packit |
ef9df4 |
# Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
|
Packit |
ef9df4 |
# This program is free software; you can redistribute it and/or
|
|
Packit |
ef9df4 |
# modify it under the same terms as Perl itself.
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
package Convert::ASN1::parser;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
use strict;
|
|
Packit |
ef9df4 |
use Convert::ASN1 qw(:all);
|
|
Packit |
ef9df4 |
use vars qw(
|
|
Packit |
ef9df4 |
$asn $yychar $yyerrflag $yynerrs $yyn @yyss
|
|
Packit |
ef9df4 |
$yyssp $yystate @yyvs $yyvsp $yylval $yys $yym $yyval
|
|
Packit |
ef9df4 |
);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
BEGIN { Convert::ASN1->_internal_syms }
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my $yydebug=0;
|
|
Packit |
ef9df4 |
my %yystate;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my %base_type = (
|
|
Packit |
ef9df4 |
BOOLEAN => [ asn_encode_tag(ASN_BOOLEAN), opBOOLEAN ],
|
|
Packit |
ef9df4 |
INTEGER => [ asn_encode_tag(ASN_INTEGER), opINTEGER ],
|
|
Packit |
ef9df4 |
BIT_STRING => [ asn_encode_tag(ASN_BIT_STR), opBITSTR ],
|
|
Packit |
ef9df4 |
OCTET_STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
|
|
Packit |
ef9df4 |
STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
|
|
Packit |
ef9df4 |
NULL => [ asn_encode_tag(ASN_NULL), opNULL ],
|
|
Packit |
ef9df4 |
OBJECT_IDENTIFIER => [ asn_encode_tag(ASN_OBJECT_ID), opOBJID ],
|
|
Packit |
ef9df4 |
REAL => [ asn_encode_tag(ASN_REAL), opREAL ],
|
|
Packit |
ef9df4 |
ENUMERATED => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
|
|
Packit |
ef9df4 |
ENUM => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
|
|
Packit |
ef9df4 |
'RELATIVE-OID' => [ asn_encode_tag(ASN_RELATIVE_OID), opROID ],
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
SEQUENCE => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opSEQUENCE ],
|
|
Packit |
ef9df4 |
EXPLICIT => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opEXPLICIT ],
|
|
Packit |
ef9df4 |
SET => [ asn_encode_tag(ASN_SET | ASN_CONSTRUCTOR), opSET ],
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
ObjectDescriptor => [ asn_encode_tag(ASN_UNIVERSAL | 7), opSTRING ],
|
|
Packit |
ef9df4 |
UTF8String => [ asn_encode_tag(ASN_UNIVERSAL | 12), opUTF8 ],
|
|
Packit |
ef9df4 |
NumericString => [ asn_encode_tag(ASN_UNIVERSAL | 18), opSTRING ],
|
|
Packit |
ef9df4 |
PrintableString => [ asn_encode_tag(ASN_UNIVERSAL | 19), opSTRING ],
|
|
Packit |
ef9df4 |
TeletexString => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
|
|
Packit |
ef9df4 |
T61String => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
|
|
Packit |
ef9df4 |
VideotexString => [ asn_encode_tag(ASN_UNIVERSAL | 21), opSTRING ],
|
|
Packit |
ef9df4 |
IA5String => [ asn_encode_tag(ASN_UNIVERSAL | 22), opSTRING ],
|
|
Packit |
ef9df4 |
UTCTime => [ asn_encode_tag(ASN_UNIVERSAL | 23), opUTIME ],
|
|
Packit |
ef9df4 |
GeneralizedTime => [ asn_encode_tag(ASN_UNIVERSAL | 24), opGTIME ],
|
|
Packit |
ef9df4 |
GraphicString => [ asn_encode_tag(ASN_UNIVERSAL | 25), opSTRING ],
|
|
Packit |
ef9df4 |
VisibleString => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
|
|
Packit |
ef9df4 |
ISO646String => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
|
|
Packit |
ef9df4 |
GeneralString => [ asn_encode_tag(ASN_UNIVERSAL | 27), opSTRING ],
|
|
Packit |
ef9df4 |
CharacterString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
|
|
Packit |
ef9df4 |
UniversalString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
|
|
Packit |
ef9df4 |
BMPString => [ asn_encode_tag(ASN_UNIVERSAL | 30), opSTRING ],
|
|
Packit |
ef9df4 |
BCDString => [ asn_encode_tag(ASN_OCTET_STR), opBCD ],
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
CHOICE => [ '', opCHOICE ],
|
|
Packit |
ef9df4 |
ANY => [ '', opANY ],
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
EXTENSION_MARKER => [ '', opEXTENSIONS ],
|
|
Packit |
ef9df4 |
);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my $tagdefault = 1; # 0:IMPLICIT , 1:EXPLICIT default
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
# args: class,plicit
|
|
Packit |
ef9df4 |
sub need_explicit {
|
|
Packit |
ef9df4 |
(defined($_[0]) && (defined($_[1])?$_[1]:$tagdefault));
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
# Given an OP, wrap it in a SEQUENCE
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub explicit {
|
|
Packit |
ef9df4 |
my $op = shift;
|
|
Packit |
ef9df4 |
my @seq = @$op;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
@seq[cTYPE,cCHILD,cVAR,cLOOP] = ('EXPLICIT',[$op],undef,undef);
|
|
Packit |
ef9df4 |
@{$op}[cTAG,cOPT] = ();
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
\@seq;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
%}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
%%
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
top : slist { $$ = { '' => $1 }; }
|
|
Packit |
ef9df4 |
| module
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
module : WORD ASSIGN aitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$$ = { $1, [$3] };
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| module WORD ASSIGN aitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$$=$1;
|
|
Packit |
ef9df4 |
$$->{$2} = [$4];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
aitem : class plicit anyelem postrb
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$3->[cTAG] = $1;
|
|
Packit |
ef9df4 |
$$ = need_explicit($1,$2) ? explicit($3) : $3;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| celem
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
anyelem : onelem
|
|
Packit |
ef9df4 |
| eelem
|
|
Packit |
ef9df4 |
| oelem
|
|
Packit |
ef9df4 |
| selem
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
celem : COMPONENTS OF WORD
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD] = ('COMPONENTS', $3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
seqset : SEQUENCE
|
|
Packit |
ef9df4 |
| SET
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
selem : seqset OF class plicit sselem optional
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$5->[cTAG] = $3;
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD,cLOOP,cOPT] = ($1, [$5], 1, $6);
|
|
Packit |
ef9df4 |
$$ = explicit($$) if need_explicit($3,$4);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sselem : eelem
|
|
Packit |
ef9df4 |
| oelem
|
|
Packit |
ef9df4 |
| onelem
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
onelem : SEQUENCE LBRACE slist RBRACE
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD] = ('SEQUENCE', $3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| SET LBRACE slist RBRACE
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD] = ('SET', $3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| CHOICE LBRACE nlist RBRACE
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD] = ('CHOICE', $3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
eelem : ENUM LBRACE elist RBRACE
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE] = ('ENUM');
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
oielem : WORD { @{$$ = []}[cTYPE] = $1; }
|
|
Packit |
ef9df4 |
| SEQUENCE { @{$$ = []}[cTYPE] = $1; }
|
|
Packit |
ef9df4 |
| SET { @{$$ = []}[cTYPE] = $1; }
|
|
Packit |
ef9df4 |
| ANY defined
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$ = []}[cTYPE,cCHILD,cDEFINE] = ('ANY',undef,$2);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| ENUM { @{$$ = []}[cTYPE] = $1; }
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
defined : { $$=undef; }
|
|
Packit |
ef9df4 |
| DEFINED BY WORD { $$=$3; }
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
oelem : oielem
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
nlist : nlist1 { $$ = $1; }
|
|
Packit |
ef9df4 |
| nlist1 POSTRBRACE { $$ = $1; }
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
nlist1 : nitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$$ = [ $1 ];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| nlist1 POSTRBRACE nitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
push @{$$=$1}, $3;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| nlist1 COMMA nitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
push @{$$=$1}, $3;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
nitem : WORD class plicit anyelem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=$4}[cVAR,cTAG] = ($1,$2);
|
|
Packit |
ef9df4 |
$$ = explicit($$) if need_explicit($2,$3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| EXTENSION_MARKER
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=[]}[cTYPE] = 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
slist : { $$ = []; }
|
|
Packit |
ef9df4 |
| slist1
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
my $extension = 0;
|
|
Packit |
ef9df4 |
$$ = [];
|
|
Packit |
ef9df4 |
for my $i (@{$1}) {
|
|
Packit |
ef9df4 |
$extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
$i->[cEXT] = $i->[cOPT];
|
|
Packit |
ef9df4 |
$i->[cEXT] = 1 if $extension;
|
|
Packit |
ef9df4 |
push @{$$}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
push @{$$}, $e if $extension;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| slist1 POSTRBRACE
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
my $extension = 0;
|
|
Packit |
ef9df4 |
$$ = [];
|
|
Packit |
ef9df4 |
for my $i (@{$1}) {
|
|
Packit |
ef9df4 |
$extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
$i->[cEXT] = $i->[cOPT];
|
|
Packit |
ef9df4 |
$i->[cEXT] = 1 if $extension;
|
|
Packit |
ef9df4 |
push @{$$}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
push @{$$}, $e if $extension;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
slist1 : sitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
$$ = [ $1 ];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| slist1 COMMA sitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
push @{$$=$1}, $3;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| slist1 POSTRBRACE sitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
push @{$$=$1}, $3;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
snitem : oelem optional
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=$1}[cOPT] = ($2);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| eelem
|
|
Packit |
ef9df4 |
| selem
|
|
Packit |
ef9df4 |
| onelem
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sitem : WORD class plicit snitem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=$4}[cVAR,cTAG] = ($1,$2);
|
|
Packit |
ef9df4 |
$$->[cOPT] = $1 if $$->[cOPT];
|
|
Packit |
ef9df4 |
$$ = explicit($$) if need_explicit($2,$3);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| celem
|
|
Packit |
ef9df4 |
| class plicit onelem
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=$3}[cTAG] = ($1);
|
|
Packit |
ef9df4 |
$$ = explicit($$) if need_explicit($1,$2);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
| EXTENSION_MARKER
|
|
Packit |
ef9df4 |
{
|
|
Packit |
ef9df4 |
@{$$=[]}[cTYPE] = 'EXTENSION_MARKER';
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
optional : { $$ = undef; }
|
|
Packit |
ef9df4 |
| OPTIONAL { $$ = 1; }
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
class : { $$ = undef; }
|
|
Packit |
ef9df4 |
| CLASS
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
plicit : { $$ = undef; }
|
|
Packit |
ef9df4 |
| EXPLICIT { $$ = 1; }
|
|
Packit |
ef9df4 |
| IMPLICIT { $$ = 0; }
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
elist : eitem {}
|
|
Packit |
ef9df4 |
| elist COMMA eitem {}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
eitem : WORD NUMBER {}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
postrb : {}
|
|
Packit |
ef9df4 |
| POSTRBRACE {}
|
|
Packit |
ef9df4 |
;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
%%
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my %reserved = (
|
|
Packit |
ef9df4 |
'OPTIONAL' => $OPTIONAL,
|
|
Packit |
ef9df4 |
'CHOICE' => $CHOICE,
|
|
Packit |
ef9df4 |
'OF' => $OF,
|
|
Packit |
ef9df4 |
'IMPLICIT' => $IMPLICIT,
|
|
Packit |
ef9df4 |
'EXPLICIT' => $EXPLICIT,
|
|
Packit |
ef9df4 |
'SEQUENCE' => $SEQUENCE,
|
|
Packit |
ef9df4 |
'SET' => $SET,
|
|
Packit |
ef9df4 |
'ANY' => $ANY,
|
|
Packit |
ef9df4 |
'ENUM' => $ENUM,
|
|
Packit |
ef9df4 |
'ENUMERATED' => $ENUM,
|
|
Packit |
ef9df4 |
'COMPONENTS' => $COMPONENTS,
|
|
Packit |
ef9df4 |
'{' => $LBRACE,
|
|
Packit |
ef9df4 |
'}' => $RBRACE,
|
|
Packit |
ef9df4 |
',' => $COMMA,
|
|
Packit |
ef9df4 |
'::=' => $ASSIGN,
|
|
Packit |
ef9df4 |
'DEFINED' => $DEFINED,
|
|
Packit |
ef9df4 |
'BY' => $BY
|
|
Packit |
ef9df4 |
);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my $reserved = join("|", reverse sort grep { /\w/ } keys %reserved);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my %tag_class = (
|
|
Packit |
ef9df4 |
APPLICATION => ASN_APPLICATION,
|
|
Packit |
ef9df4 |
UNIVERSAL => ASN_UNIVERSAL,
|
|
Packit |
ef9df4 |
PRIVATE => ASN_PRIVATE,
|
|
Packit |
ef9df4 |
CONTEXT => ASN_CONTEXT,
|
|
Packit |
ef9df4 |
'' => ASN_CONTEXT # if not specified, its CONTEXT
|
|
Packit |
ef9df4 |
);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
;##
|
|
Packit |
ef9df4 |
;## This is NOT thread safe !!!!!!
|
|
Packit |
ef9df4 |
;##
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
my $pos;
|
|
Packit |
ef9df4 |
my $last_pos;
|
|
Packit |
ef9df4 |
my @stacked;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub parse {
|
|
Packit |
ef9df4 |
local(*asn) = \($_[0]);
|
|
Packit |
ef9df4 |
$tagdefault = $_[1] eq 'EXPLICIT' ? 1 : 0;
|
|
Packit |
ef9df4 |
($pos,$last_pos,@stacked) = ();
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
eval {
|
|
Packit |
ef9df4 |
local $SIG{__DIE__};
|
|
Packit |
ef9df4 |
compile(verify(yyparse()));
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub compile_one {
|
|
Packit |
ef9df4 |
my $tree = shift;
|
|
Packit |
ef9df4 |
my $ops = shift;
|
|
Packit |
ef9df4 |
my $name = shift;
|
|
Packit |
ef9df4 |
foreach my $op (@$ops) {
|
|
Packit |
ef9df4 |
next unless ref($op) eq 'ARRAY';
|
|
Packit |
ef9df4 |
bless $op;
|
|
Packit |
ef9df4 |
my $type = $op->[cTYPE];
|
|
Packit |
ef9df4 |
if (exists $base_type{$type}) {
|
|
Packit |
ef9df4 |
$op->[cTYPE] = $base_type{$type}->[1];
|
|
Packit |
ef9df4 |
$op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $base_type{$type}->[0];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
else {
|
|
Packit |
ef9df4 |
die "Unknown type '$type'\n" unless exists $tree->{$type};
|
|
Packit |
ef9df4 |
my $ref = compile_one(
|
|
Packit |
ef9df4 |
$tree,
|
|
Packit |
ef9df4 |
$tree->{$type},
|
|
Packit |
ef9df4 |
defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name
|
|
Packit |
ef9df4 |
);
|
|
Packit |
ef9df4 |
if (defined($op->[cTAG]) && $ref->[0][cTYPE] == opCHOICE) {
|
|
Packit |
ef9df4 |
@{$op}[cTYPE,cCHILD] = (opSEQUENCE,$ref);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
else {
|
|
Packit |
ef9df4 |
@{$op}[cTYPE,cCHILD,cLOOP] = @{$ref->[0]}[cTYPE,cCHILD,cLOOP];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
$op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $ref->[0][cTAG];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
$op->[cTAG] |= pack("C",ASN_CONSTRUCTOR)
|
|
Packit |
ef9df4 |
if length $op->[cTAG] && ($op->[cTYPE] == opSET || $op->[cTYPE] == opEXPLICIT || $op->[cTYPE] == opSEQUENCE);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if ($op->[cCHILD]) {
|
|
Packit |
ef9df4 |
;# If we have children we are one of
|
|
Packit |
ef9df4 |
;# opSET opSEQUENCE opCHOICE opEXPLICIT
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
compile_one($tree, $op->[cCHILD], defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
;# If a CHOICE is given a tag, then it must be EXPLICIT
|
|
Packit |
ef9df4 |
if ($op->[cTYPE] == opCHOICE && defined($op->[cTAG]) && length($op->[cTAG])) {
|
|
Packit |
ef9df4 |
$op = bless explicit($op);
|
|
Packit |
ef9df4 |
$op->[cTYPE] = opSEQUENCE;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if ( @{$op->[cCHILD]} > 1) {
|
|
Packit |
ef9df4 |
;#if ($op->[cTYPE] != opSEQUENCE) {
|
|
Packit |
ef9df4 |
;# Here we need to flatten CHOICEs and check that SET and CHOICE
|
|
Packit |
ef9df4 |
;# do not contain duplicate tags
|
|
Packit |
ef9df4 |
;#}
|
|
Packit |
ef9df4 |
if ($op->[cTYPE] == opSET) {
|
|
Packit |
ef9df4 |
;# In case we do CER encoding we order the SET elements by thier tags
|
|
Packit |
ef9df4 |
my @tags = map {
|
|
Packit |
ef9df4 |
length($_->[cTAG])
|
|
Packit |
ef9df4 |
? $_->[cTAG]
|
|
Packit |
ef9df4 |
: $_->[cTYPE] == opCHOICE
|
|
Packit |
ef9df4 |
? (sort map { $_->[cTAG] } $_->[cCHILD])[0]
|
|
Packit |
ef9df4 |
: ''
|
|
Packit |
ef9df4 |
} @{$op->[cCHILD]};
|
|
Packit |
ef9df4 |
@{$op->[cCHILD]} = @{$op->[cCHILD]}[sort { $tags[$a] cmp $tags[$b] } 0..$#tags];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
else {
|
|
Packit |
ef9df4 |
;# A SET of one element can be treated the same as a SEQUENCE
|
|
Packit |
ef9df4 |
$op->[cTYPE] = opSEQUENCE if $op->[cTYPE] == opSET;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
$ops;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub compile {
|
|
Packit |
ef9df4 |
my $tree = shift;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
;# The tree should be valid enough to be able to
|
|
Packit |
ef9df4 |
;# - resolve references
|
|
Packit |
ef9df4 |
;# - encode tags
|
|
Packit |
ef9df4 |
;# - verify CHOICEs do not contain duplicate tags
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
;# once references have been resolved, and also due to
|
|
Packit |
ef9df4 |
;# flattening of COMPONENTS, it is possible for an op
|
|
Packit |
ef9df4 |
;# to appear in multiple places. So once an op is
|
|
Packit |
ef9df4 |
;# compiled we bless it. This ensure we dont try to
|
|
Packit |
ef9df4 |
;# compile it again.
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
while(my($k,$v) = each %$tree) {
|
|
Packit |
ef9df4 |
compile_one($tree,$v,$k);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
$tree;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub verify {
|
|
Packit |
ef9df4 |
my $tree = shift or return;
|
|
Packit |
ef9df4 |
my $err = "";
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
;# Well it parsed correctly, now we
|
|
Packit |
ef9df4 |
;# - check references exist
|
|
Packit |
ef9df4 |
;# - flatten COMPONENTS OF (checking for loops)
|
|
Packit |
ef9df4 |
;# - check for duplicate var names
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
while(my($name,$ops) = each %$tree) {
|
|
Packit |
ef9df4 |
my $stash = {};
|
|
Packit |
ef9df4 |
my @scope = ();
|
|
Packit |
ef9df4 |
my $path = "";
|
|
Packit |
ef9df4 |
my $idx = 0;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
while($ops) {
|
|
Packit |
ef9df4 |
if ($idx < @$ops) {
|
|
Packit |
ef9df4 |
my $op = $ops->[$idx++];
|
|
Packit |
ef9df4 |
my $var;
|
|
Packit |
ef9df4 |
if (defined ($var = $op->[cVAR])) {
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
$err .= "$name: $path.$var used multiple times\n"
|
|
Packit |
ef9df4 |
if $stash->{$var}++;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
if (defined $op->[cCHILD]) {
|
|
Packit |
ef9df4 |
if (ref $op->[cCHILD]) {
|
|
Packit |
ef9df4 |
push @scope, [$stash, $path, $ops, $idx];
|
|
Packit |
ef9df4 |
if (defined $var) {
|
|
Packit |
ef9df4 |
$stash = {};
|
|
Packit |
ef9df4 |
$path .= "." . $var;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
$idx = 0;
|
|
Packit |
ef9df4 |
$ops = $op->[cCHILD];
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
elsif ($op->[cTYPE] eq 'COMPONENTS') {
|
|
Packit |
ef9df4 |
splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD]));
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
else {
|
|
Packit |
ef9df4 |
die "Internal error\n";
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
else {
|
|
Packit |
ef9df4 |
my $s = pop @scope
|
|
Packit |
ef9df4 |
or last;
|
|
Packit |
ef9df4 |
($stash,$path,$ops,$idx) = @$s;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
die $err if length $err;
|
|
Packit |
ef9df4 |
$tree;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub expand_ops {
|
|
Packit |
ef9df4 |
my $tree = shift;
|
|
Packit |
ef9df4 |
my $want = shift;
|
|
Packit |
ef9df4 |
my $seen = shift || { };
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
die "COMPONENTS OF loop $want\n" if $seen->{$want}++;
|
|
Packit |
ef9df4 |
die "Undefined macro $want\n" unless exists $tree->{$want};
|
|
Packit |
ef9df4 |
my $ops = $tree->{$want};
|
|
Packit |
ef9df4 |
die "Bad macro for COMPUNENTS OF '$want'\n"
|
|
Packit |
ef9df4 |
unless @$ops == 1
|
|
Packit |
ef9df4 |
&& ($ops->[0][cTYPE] eq 'SEQUENCE' || $ops->[0][cTYPE] eq 'SET')
|
|
Packit |
ef9df4 |
&& ref $ops->[0][cCHILD];
|
|
Packit |
ef9df4 |
$ops = $ops->[0][cCHILD];
|
|
Packit |
ef9df4 |
for(my $idx = 0 ; $idx < @$ops ; ) {
|
|
Packit |
ef9df4 |
my $op = $ops->[$idx++];
|
|
Packit |
ef9df4 |
if ($op->[cTYPE] eq 'COMPONENTS') {
|
|
Packit |
ef9df4 |
splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD], $seen));
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
@$ops;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub _yylex {
|
|
Packit |
ef9df4 |
my $ret = &_yylex;
|
|
Packit |
ef9df4 |
warn $ret;
|
|
Packit |
ef9df4 |
$ret;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub yylex {
|
|
Packit |
ef9df4 |
return shift @stacked if @stacked;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
while ($asn =~ /\G(?:
|
|
Packit |
ef9df4 |
(\s+|--[^\n]*)
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
([,{}]|::=)
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
($reserved)\b
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
(
|
|
Packit |
ef9df4 |
(?:OCTET|BIT)\s+STRING
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
OBJECT\s+IDENTIFIER
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
RELATIVE-OID
|
|
Packit |
ef9df4 |
)\b
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
(\w+(?:-\w+)*)
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
\[\s*
|
|
Packit |
ef9df4 |
(
|
|
Packit |
ef9df4 |
(?:(?:APPLICATION|PRIVATE|UNIVERSAL|CONTEXT)\s+)?
|
|
Packit |
ef9df4 |
\d+
|
|
Packit |
ef9df4 |
)
|
|
Packit |
ef9df4 |
\s*\]
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
\((\d+)\)
|
|
Packit |
ef9df4 |
|
|
|
Packit |
ef9df4 |
(\.\.\.)
|
|
Packit |
ef9df4 |
)/sxgo
|
|
Packit |
ef9df4 |
) {
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
($last_pos,$pos) = ($pos,pos($asn));
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
next if defined $1; # comment or whitespace
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $2 or defined $3) {
|
|
Packit |
ef9df4 |
my $ret = $+;
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
# A comma is not required after a '}' so to aid the
|
|
Packit |
ef9df4 |
# parser we insert a fake token after any '}'
|
|
Packit |
ef9df4 |
if ($ret eq '}') {
|
|
Packit |
ef9df4 |
my $p = pos($asn);
|
|
Packit |
ef9df4 |
my @tmp = @stacked;
|
|
Packit |
ef9df4 |
@stacked = ();
|
|
Packit |
ef9df4 |
pos($asn) = $p if yylex() != $COMMA; # swallow it
|
|
Packit |
ef9df4 |
@stacked = (@tmp, $POSTRBRACE);
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
return $reserved{$yylval = $ret};
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $4) {
|
|
Packit |
ef9df4 |
($yylval = $+) =~ s/\s+/_/g;
|
|
Packit |
ef9df4 |
return $WORD;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $5) {
|
|
Packit |
ef9df4 |
$yylval = $+;
|
|
Packit |
ef9df4 |
return $WORD;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $6) {
|
|
Packit |
ef9df4 |
my($class,$num) = ($+ =~ /^([A-Z]*)\s*(\d+)$/);
|
|
Packit |
ef9df4 |
$yylval = asn_tag($tag_class{$class}, $num);
|
|
Packit |
ef9df4 |
return $CLASS;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $7) {
|
|
Packit |
ef9df4 |
$yylval = $+;
|
|
Packit |
ef9df4 |
return $NUMBER;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
if (defined $8) {
|
|
Packit |
ef9df4 |
return $EXTENSION_MARKER;
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
die "Internal error\n";
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
die "Parse error before ",substr($asn,$pos,40),"\n"
|
|
Packit |
ef9df4 |
unless $pos == length($asn);
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
0
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
sub yyerror {
|
|
Packit |
ef9df4 |
die @_," ",substr($asn,$last_pos,40),"\n";
|
|
Packit |
ef9df4 |
}
|
|
Packit |
ef9df4 |
|
|
Packit |
ef9df4 |
1;
|
|
Packit |
ef9df4 |
|