1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
111
  
112
  
113
  
114
  
115
  
116
  
117
  
118
  
119
  
/* asn1.pmod.pike 
 * 
 * Rudimentary support for decoding ASN.1 encoded data. 
 * 
 * $Id: asn1.pmod.pike,v 1.3 1997/03/15 12:15:07 nisse Exp $ 
 */ 
 
/* BER decoder 
 * 
 * Values are represented as arrays ({ tag, value }). 
 * Tag is either an integer tag number, or a string, in case 
 * the tag recognized. 
 * 
 * Values are strings, integers, or arrays */ 
 
class ber_decode { 
  inherit ADT.struct; 
 
  array get_asn1() 
  { 
    int|string tag = get_int(1); 
    int len; 
    string contents; 
    mixed value; 
     
#ifdef SSL3_DEBUG 
    werror(sprintf("decoding tag %x\n", tag)); 
#endif 
    if ( (tag & 0x1f) == 0x1f) 
      throw( ({ "high tag numbers is not supported\n", backtrace() }) ); 
    int len = get_int(1); 
    if (len & 0x80) 
      len = get_int(len & 0x7f); 
     
#ifdef SSL3_DEBUG 
    werror(sprintf("len : %d\n", len)); 
#endif 
    contents = get_fix_string(len); 
#ifdef SSL3_DEBUG 
    werror(sprintf("contents: %O\n", contents)); 
#endif 
    if (tag & 0x20) 
    { 
      object seq = object_program(this_object())(contents); 
      value = ({ }); 
      while(! seq->is_empty()) 
      { 
        array elem = seq->get_asn1(); 
#ifdef SSL3_DEBUG 
      // werror(sprintf("elem: %O\n", elem)); 
#endif 
      value += ({ elem }); 
      } 
    } 
    switch(tag & 0xdf) 
    { 
    case 1: /* Boolean */ 
      if (strlen(contents) != 1) 
        throw( ({ "SSL.asn1: Invalid boolean value.\n", backtrace() }) ); 
      tag = "BOOLEAN"; 
      value = !!contents[0]; 
      break; 
    case 2: /* Integer */ 
      tag = "INTEGER"; 
      value = Gmp.mpz(contents, 256); 
      if (contents[0] & 0x80)  /* Negative */ 
        value -= Gmp.pow(256, strlen(contents)); 
      break; 
    case 3: /* Bit string */ 
      tag = "BIT STRING"; 
      break; 
    case 4: /* Octet string */ 
      tag = "OCTET STRING"; 
      break; 
    case 5: /* Null */ 
      if (strlen(contents)) 
        throw( ({ "SSL.asn1: Invalid NULL value.\n", backtrace() }) ); 
      break; 
    case 6: /* Object id */ 
    { 
      tag = "Identifier"; 
      if (contents[0] < 120) 
        value = ({ contents[0] / 40, contents[0] % 40 }); 
      else 
        value = ({ 2, contents[0] - 80 }); 
      int index = 1; 
      while(index < strlen(contents)) 
      { 
        int id = 0; 
        do 
        { 
          id = id << 7 | (contents[index] & 0x7f); 
        } while(contents[index++] & 0x80); 
        value += ({ id }); 
      } 
      break; 
    } 
    case 9: /* Real */ 
      tag = "REAL"; 
      break; 
    case 10: /* Enumerated */ 
      tag = "ENUMERATED"; 
      break; 
    case 16: /* Sequence */ 
      tag = "SEQUENCE"; 
      break; 
    case 17: /* Set */ 
      tag = "SET"; 
      break; 
    default: /* Keep numeric tag */ 
      break; 
    } 
       
    return ({ tag, value }); 
  } 
}