PageRenderTime 111ms CodeModel.GetById 52ms RepoModel.GetById 0ms app.codeStats 1ms

/Convert-ASN1-0.26/parser.y

#
Happy | 637 lines | 544 code | 93 blank | 0 comment | 0 complexity | c107c3b2d2efffd59a805d045dddaea5 MD5 | raw file
Possible License(s): AGPL-1.0
  1. %token WORD 1
  2. %token CLASS 2
  3. %token SEQUENCE 3
  4. %token SET 4
  5. %token CHOICE 5
  6. %token OF 6
  7. %token IMPLICIT 7
  8. %token EXPLICIT 8
  9. %token OPTIONAL 9
  10. %token LBRACE 10
  11. %token RBRACE 11
  12. %token COMMA 12
  13. %token ANY 13
  14. %token ASSIGN 14
  15. %token NUMBER 15
  16. %token ENUM 16
  17. %token COMPONENTS 17
  18. %token POSTRBRACE 18
  19. %token DEFINED 19
  20. %token BY 20
  21. %token EXTENSION_MARKER 21
  22. %{
  23. # Copyright (c) 2000-2005 Graham Barr <gbarr@pobox.com>. All rights reserved.
  24. # This program is free software; you can redistribute it and/or
  25. # modify it under the same terms as Perl itself.
  26. package Convert::ASN1::parser;
  27. use strict;
  28. use Convert::ASN1 qw(:all);
  29. use vars qw(
  30. $asn $yychar $yyerrflag $yynerrs $yyn @yyss
  31. $yyssp $yystate @yyvs $yyvsp $yylval $yys $yym $yyval
  32. );
  33. BEGIN { Convert::ASN1->_internal_syms }
  34. my $yydebug=0;
  35. my %yystate;
  36. my %base_type = (
  37. BOOLEAN => [ asn_encode_tag(ASN_BOOLEAN), opBOOLEAN ],
  38. INTEGER => [ asn_encode_tag(ASN_INTEGER), opINTEGER ],
  39. BIT_STRING => [ asn_encode_tag(ASN_BIT_STR), opBITSTR ],
  40. OCTET_STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
  41. STRING => [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
  42. NULL => [ asn_encode_tag(ASN_NULL), opNULL ],
  43. OBJECT_IDENTIFIER => [ asn_encode_tag(ASN_OBJECT_ID), opOBJID ],
  44. REAL => [ asn_encode_tag(ASN_REAL), opREAL ],
  45. ENUMERATED => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
  46. ENUM => [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
  47. 'RELATIVE-OID' => [ asn_encode_tag(ASN_RELATIVE_OID), opROID ],
  48. SEQUENCE => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opSEQUENCE ],
  49. EXPLICIT => [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opEXPLICIT ],
  50. SET => [ asn_encode_tag(ASN_SET | ASN_CONSTRUCTOR), opSET ],
  51. ObjectDescriptor => [ asn_encode_tag(ASN_UNIVERSAL | 7), opSTRING ],
  52. UTF8String => [ asn_encode_tag(ASN_UNIVERSAL | 12), opUTF8 ],
  53. NumericString => [ asn_encode_tag(ASN_UNIVERSAL | 18), opSTRING ],
  54. PrintableString => [ asn_encode_tag(ASN_UNIVERSAL | 19), opSTRING ],
  55. TeletexString => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
  56. T61String => [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
  57. VideotexString => [ asn_encode_tag(ASN_UNIVERSAL | 21), opSTRING ],
  58. IA5String => [ asn_encode_tag(ASN_UNIVERSAL | 22), opSTRING ],
  59. UTCTime => [ asn_encode_tag(ASN_UNIVERSAL | 23), opUTIME ],
  60. GeneralizedTime => [ asn_encode_tag(ASN_UNIVERSAL | 24), opGTIME ],
  61. GraphicString => [ asn_encode_tag(ASN_UNIVERSAL | 25), opSTRING ],
  62. VisibleString => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
  63. ISO646String => [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
  64. GeneralString => [ asn_encode_tag(ASN_UNIVERSAL | 27), opSTRING ],
  65. CharacterString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
  66. UniversalString => [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
  67. BMPString => [ asn_encode_tag(ASN_UNIVERSAL | 30), opSTRING ],
  68. BCDString => [ asn_encode_tag(ASN_OCTET_STR), opBCD ],
  69. CHOICE => [ '', opCHOICE ],
  70. ANY => [ '', opANY ],
  71. EXTENSION_MARKER => [ '', opEXTENSIONS ],
  72. );
  73. my $tagdefault = 1; # 0:IMPLICIT , 1:EXPLICIT default
  74. # args: class,plicit
  75. sub need_explicit {
  76. (defined($_[0]) && (defined($_[1])?$_[1]:$tagdefault));
  77. }
  78. # Given an OP, wrap it in a SEQUENCE
  79. sub explicit {
  80. my $op = shift;
  81. my @seq = @$op;
  82. @seq[cTYPE,cCHILD,cVAR,cLOOP] = ('EXPLICIT',[$op],undef,undef);
  83. @{$op}[cTAG,cOPT] = ();
  84. \@seq;
  85. }
  86. %}
  87. %%
  88. top : slist { $$ = { '' => $1 }; }
  89. | module
  90. ;
  91. module : WORD ASSIGN aitem
  92. {
  93. $$ = { $1, [$3] };
  94. }
  95. | module WORD ASSIGN aitem
  96. {
  97. $$=$1;
  98. $$->{$2} = [$4];
  99. }
  100. ;
  101. aitem : class plicit anyelem postrb
  102. {
  103. $3->[cTAG] = $1;
  104. $$ = need_explicit($1,$2) ? explicit($3) : $3;
  105. }
  106. | celem
  107. ;
  108. anyelem : onelem
  109. | eelem
  110. | oelem
  111. | selem
  112. ;
  113. celem : COMPONENTS OF WORD
  114. {
  115. @{$$ = []}[cTYPE,cCHILD] = ('COMPONENTS', $3);
  116. }
  117. ;
  118. seqset : SEQUENCE
  119. | SET
  120. ;
  121. selem : seqset OF class plicit sselem optional
  122. {
  123. $5->[cTAG] = $3;
  124. @{$$ = []}[cTYPE,cCHILD,cLOOP,cOPT] = ($1, [$5], 1, $6);
  125. $$ = explicit($$) if need_explicit($3,$4);
  126. }
  127. ;
  128. sselem : eelem
  129. | oelem
  130. | onelem
  131. ;
  132. onelem : SEQUENCE LBRACE slist RBRACE
  133. {
  134. @{$$ = []}[cTYPE,cCHILD] = ('SEQUENCE', $3);
  135. }
  136. | SET LBRACE slist RBRACE
  137. {
  138. @{$$ = []}[cTYPE,cCHILD] = ('SET', $3);
  139. }
  140. | CHOICE LBRACE nlist RBRACE
  141. {
  142. @{$$ = []}[cTYPE,cCHILD] = ('CHOICE', $3);
  143. }
  144. ;
  145. eelem : ENUM LBRACE elist RBRACE
  146. {
  147. @{$$ = []}[cTYPE] = ('ENUM');
  148. }
  149. ;
  150. oielem : WORD { @{$$ = []}[cTYPE] = $1; }
  151. | SEQUENCE { @{$$ = []}[cTYPE] = $1; }
  152. | SET { @{$$ = []}[cTYPE] = $1; }
  153. | ANY defined
  154. {
  155. @{$$ = []}[cTYPE,cCHILD,cDEFINE] = ('ANY',undef,$2);
  156. }
  157. | ENUM { @{$$ = []}[cTYPE] = $1; }
  158. ;
  159. defined : { $$=undef; }
  160. | DEFINED BY WORD { $$=$3; }
  161. ;
  162. oelem : oielem
  163. ;
  164. nlist : nlist1 { $$ = $1; }
  165. | nlist1 POSTRBRACE { $$ = $1; }
  166. ;
  167. nlist1 : nitem
  168. {
  169. $$ = [ $1 ];
  170. }
  171. | nlist1 POSTRBRACE nitem
  172. {
  173. push @{$$=$1}, $3;
  174. }
  175. | nlist1 COMMA nitem
  176. {
  177. push @{$$=$1}, $3;
  178. }
  179. ;
  180. nitem : WORD class plicit anyelem
  181. {
  182. @{$$=$4}[cVAR,cTAG] = ($1,$2);
  183. $$ = explicit($$) if need_explicit($2,$3);
  184. }
  185. | EXTENSION_MARKER
  186. {
  187. @{$$=[]}[cTYPE] = 'EXTENSION_MARKER';
  188. }
  189. ;
  190. slist : { $$ = []; }
  191. | slist1
  192. {
  193. my $extension = 0;
  194. $$ = [];
  195. for my $i (@{$1}) {
  196. $extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
  197. $i->[cEXT] = $i->[cOPT];
  198. $i->[cEXT] = 1 if $extension;
  199. push @{$$}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
  200. }
  201. my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
  202. push @{$$}, $e if $extension;
  203. }
  204. | slist1 POSTRBRACE
  205. {
  206. my $extension = 0;
  207. $$ = [];
  208. for my $i (@{$1}) {
  209. $extension = 1 if $i->[cTYPE] eq 'EXTENSION_MARKER';
  210. $i->[cEXT] = $i->[cOPT];
  211. $i->[cEXT] = 1 if $extension;
  212. push @{$$}, $i unless $i->[cTYPE] eq 'EXTENSION_MARKER';
  213. }
  214. my $e = []; $e->[cTYPE] = 'EXTENSION_MARKER';
  215. push @{$$}, $e if $extension;
  216. }
  217. ;
  218. slist1 : sitem
  219. {
  220. $$ = [ $1 ];
  221. }
  222. | slist1 COMMA sitem
  223. {
  224. push @{$$=$1}, $3;
  225. }
  226. | slist1 POSTRBRACE sitem
  227. {
  228. push @{$$=$1}, $3;
  229. }
  230. ;
  231. snitem : oelem optional
  232. {
  233. @{$$=$1}[cOPT] = ($2);
  234. }
  235. | eelem
  236. | selem
  237. | onelem
  238. ;
  239. sitem : WORD class plicit snitem
  240. {
  241. @{$$=$4}[cVAR,cTAG] = ($1,$2);
  242. $$->[cOPT] = $1 if $$->[cOPT];
  243. $$ = explicit($$) if need_explicit($2,$3);
  244. }
  245. | celem
  246. | class plicit onelem
  247. {
  248. @{$$=$3}[cTAG] = ($1);
  249. $$ = explicit($$) if need_explicit($1,$2);
  250. }
  251. | EXTENSION_MARKER
  252. {
  253. @{$$=[]}[cTYPE] = 'EXTENSION_MARKER';
  254. }
  255. ;
  256. optional : { $$ = undef; }
  257. | OPTIONAL { $$ = 1; }
  258. ;
  259. class : { $$ = undef; }
  260. | CLASS
  261. ;
  262. plicit : { $$ = undef; }
  263. | EXPLICIT { $$ = 1; }
  264. | IMPLICIT { $$ = 0; }
  265. ;
  266. elist : eitem {}
  267. | elist COMMA eitem {}
  268. ;
  269. eitem : WORD NUMBER {}
  270. ;
  271. postrb : {}
  272. | POSTRBRACE {}
  273. ;
  274. %%
  275. my %reserved = (
  276. 'OPTIONAL' => $OPTIONAL,
  277. 'CHOICE' => $CHOICE,
  278. 'OF' => $OF,
  279. 'IMPLICIT' => $IMPLICIT,
  280. 'EXPLICIT' => $EXPLICIT,
  281. 'SEQUENCE' => $SEQUENCE,
  282. 'SET' => $SET,
  283. 'ANY' => $ANY,
  284. 'ENUM' => $ENUM,
  285. 'ENUMERATED' => $ENUM,
  286. 'COMPONENTS' => $COMPONENTS,
  287. '{' => $LBRACE,
  288. '}' => $RBRACE,
  289. ',' => $COMMA,
  290. '::=' => $ASSIGN,
  291. 'DEFINED' => $DEFINED,
  292. 'BY' => $BY
  293. );
  294. my $reserved = join("|", reverse sort grep { /\w/ } keys %reserved);
  295. my %tag_class = (
  296. APPLICATION => ASN_APPLICATION,
  297. UNIVERSAL => ASN_UNIVERSAL,
  298. PRIVATE => ASN_PRIVATE,
  299. CONTEXT => ASN_CONTEXT,
  300. '' => ASN_CONTEXT # if not specified, its CONTEXT
  301. );
  302. ;##
  303. ;## This is NOT thread safe !!!!!!
  304. ;##
  305. my $pos;
  306. my $last_pos;
  307. my @stacked;
  308. sub parse {
  309. local(*asn) = \($_[0]);
  310. $tagdefault = $_[1] eq 'EXPLICIT' ? 1 : 0;
  311. ($pos,$last_pos,@stacked) = ();
  312. eval {
  313. local $SIG{__DIE__};
  314. compile(verify(yyparse()));
  315. }
  316. }
  317. sub compile_one {
  318. my $tree = shift;
  319. my $ops = shift;
  320. my $name = shift;
  321. foreach my $op (@$ops) {
  322. next unless ref($op) eq 'ARRAY';
  323. bless $op;
  324. my $type = $op->[cTYPE];
  325. if (exists $base_type{$type}) {
  326. $op->[cTYPE] = $base_type{$type}->[1];
  327. $op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $base_type{$type}->[0];
  328. }
  329. else {
  330. die "Unknown type '$type'\n" unless exists $tree->{$type};
  331. my $ref = compile_one(
  332. $tree,
  333. $tree->{$type},
  334. defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name
  335. );
  336. if (defined($op->[cTAG]) && $ref->[0][cTYPE] == opCHOICE) {
  337. @{$op}[cTYPE,cCHILD] = (opSEQUENCE,$ref);
  338. }
  339. else {
  340. @{$op}[cTYPE,cCHILD,cLOOP] = @{$ref->[0]}[cTYPE,cCHILD,cLOOP];
  341. }
  342. $op->[cTAG] = defined($op->[cTAG]) ? asn_encode_tag($op->[cTAG]): $ref->[0][cTAG];
  343. }
  344. $op->[cTAG] |= chr(ASN_CONSTRUCTOR)
  345. if length $op->[cTAG] && ($op->[cTYPE] == opSET || $op->[cTYPE] == opEXPLICIT || $op->[cTYPE] == opSEQUENCE);
  346. if ($op->[cCHILD]) {
  347. ;# If we have children we are one of
  348. ;# opSET opSEQUENCE opCHOICE opEXPLICIT
  349. compile_one($tree, $op->[cCHILD], defined($op->[cVAR]) ? $name . "." . $op->[cVAR] : $name);
  350. ;# If a CHOICE is given a tag, then it must be EXPLICIT
  351. if ($op->[cTYPE] == opCHOICE && defined($op->[cTAG]) && length($op->[cTAG])) {
  352. $op = bless explicit($op);
  353. $op->[cTYPE] = opSEQUENCE;
  354. }
  355. if ( @{$op->[cCHILD]} > 1) {
  356. ;#if ($op->[cTYPE] != opSEQUENCE) {
  357. ;# Here we need to flatten CHOICEs and check that SET and CHOICE
  358. ;# do not contain duplicate tags
  359. ;#}
  360. if ($op->[cTYPE] == opSET) {
  361. ;# In case we do CER encoding we order the SET elements by thier tags
  362. my @tags = map {
  363. length($_->[cTAG])
  364. ? $_->[cTAG]
  365. : $_->[cTYPE] == opCHOICE
  366. ? (sort map { $_->[cTAG] } $_->[cCHILD])[0]
  367. : ''
  368. } @{$op->[cCHILD]};
  369. @{$op->[cCHILD]} = @{$op->[cCHILD]}[sort { $tags[$a] cmp $tags[$b] } 0..$#tags];
  370. }
  371. }
  372. else {
  373. ;# A SET of one element can be treated the same as a SEQUENCE
  374. $op->[cTYPE] = opSEQUENCE if $op->[cTYPE] == opSET;
  375. }
  376. }
  377. }
  378. $ops;
  379. }
  380. sub compile {
  381. my $tree = shift;
  382. ;# The tree should be valid enough to be able to
  383. ;# - resolve references
  384. ;# - encode tags
  385. ;# - verify CHOICEs do not contain duplicate tags
  386. ;# once references have been resolved, and also due to
  387. ;# flattening of COMPONENTS, it is possible for an op
  388. ;# to appear in multiple places. So once an op is
  389. ;# compiled we bless it. This ensure we dont try to
  390. ;# compile it again.
  391. while(my($k,$v) = each %$tree) {
  392. compile_one($tree,$v,$k);
  393. }
  394. $tree;
  395. }
  396. sub verify {
  397. my $tree = shift or return;
  398. my $err = "";
  399. ;# Well it parsed correctly, now we
  400. ;# - check references exist
  401. ;# - flatten COMPONENTS OF (checking for loops)
  402. ;# - check for duplicate var names
  403. while(my($name,$ops) = each %$tree) {
  404. my $stash = {};
  405. my @scope = ();
  406. my $path = "";
  407. my $idx = 0;
  408. while($ops) {
  409. if ($idx < @$ops) {
  410. my $op = $ops->[$idx++];
  411. my $var;
  412. if (defined ($var = $op->[cVAR])) {
  413. $err .= "$name: $path.$var used multiple times\n"
  414. if $stash->{$var}++;
  415. }
  416. if (defined $op->[cCHILD]) {
  417. if (ref $op->[cCHILD]) {
  418. push @scope, [$stash, $path, $ops, $idx];
  419. if (defined $var) {
  420. $stash = {};
  421. $path .= "." . $var;
  422. }
  423. $idx = 0;
  424. $ops = $op->[cCHILD];
  425. }
  426. elsif ($op->[cTYPE] eq 'COMPONENTS') {
  427. splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD]));
  428. }
  429. else {
  430. die "Internal error\n";
  431. }
  432. }
  433. }
  434. else {
  435. my $s = pop @scope
  436. or last;
  437. ($stash,$path,$ops,$idx) = @$s;
  438. }
  439. }
  440. }
  441. die $err if length $err;
  442. $tree;
  443. }
  444. sub expand_ops {
  445. my $tree = shift;
  446. my $want = shift;
  447. my $seen = shift || { };
  448. die "COMPONENTS OF loop $want\n" if $seen->{$want}++;
  449. die "Undefined macro $want\n" unless exists $tree->{$want};
  450. my $ops = $tree->{$want};
  451. die "Bad macro for COMPUNENTS OF '$want'\n"
  452. unless @$ops == 1
  453. && ($ops->[0][cTYPE] eq 'SEQUENCE' || $ops->[0][cTYPE] eq 'SET')
  454. && ref $ops->[0][cCHILD];
  455. $ops = $ops->[0][cCHILD];
  456. for(my $idx = 0 ; $idx < @$ops ; ) {
  457. my $op = $ops->[$idx++];
  458. if ($op->[cTYPE] eq 'COMPONENTS') {
  459. splice(@$ops,--$idx,1,expand_ops($tree, $op->[cCHILD], $seen));
  460. }
  461. }
  462. @$ops;
  463. }
  464. sub _yylex {
  465. my $ret = &_yylex;
  466. warn $ret;
  467. $ret;
  468. }
  469. sub yylex {
  470. return shift @stacked if @stacked;
  471. while ($asn =~ /\G(?:
  472. (\s+|--[^\n]*)
  473. |
  474. ([,{}]|::=)
  475. |
  476. ($reserved)\b
  477. |
  478. (
  479. (?:OCTET|BIT)\s+STRING
  480. |
  481. OBJECT\s+IDENTIFIER
  482. |
  483. RELATIVE-OID
  484. )\b
  485. |
  486. (\w+(?:-\w+)*)
  487. |
  488. \[\s*
  489. (
  490. (?:(?:APPLICATION|PRIVATE|UNIVERSAL|CONTEXT)\s+)?
  491. \d+
  492. )
  493. \s*\]
  494. |
  495. \((\d+)\)
  496. |
  497. (\.\.\.)
  498. )/sxgo
  499. ) {
  500. ($last_pos,$pos) = ($pos,pos($asn));
  501. next if defined $1; # comment or whitespace
  502. if (defined $2 or defined $3) {
  503. my $ret = $+;
  504. # A comma is not required after a '}' so to aid the
  505. # parser we insert a fake token after any '}'
  506. if ($ret eq '}') {
  507. my $p = pos($asn);
  508. my @tmp = @stacked;
  509. @stacked = ();
  510. pos($asn) = $p if yylex() != $COMMA; # swallow it
  511. @stacked = (@tmp, $POSTRBRACE);
  512. }
  513. return $reserved{$yylval = $ret};
  514. }
  515. if (defined $4) {
  516. ($yylval = $+) =~ s/\s+/_/g;
  517. return $WORD;
  518. }
  519. if (defined $5) {
  520. $yylval = $+;
  521. return $WORD;
  522. }
  523. if (defined $6) {
  524. my($class,$num) = ($+ =~ /^([A-Z]*)\s*(\d+)$/);
  525. $yylval = asn_tag($tag_class{$class}, $num);
  526. return $CLASS;
  527. }
  528. if (defined $7) {
  529. $yylval = $+;
  530. return $NUMBER;
  531. }
  532. if (defined $8) {
  533. return $EXTENSION_MARKER;
  534. }
  535. die "Internal error\n";
  536. }
  537. die "Parse error before ",substr($asn,$pos,40),"\n"
  538. unless $pos == length($asn);
  539. 0
  540. }
  541. sub yyerror {
  542. die @_," ",substr($asn,$last_pos,40),"\n";
  543. }
  544. 1;