1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# This file implements very minimal ASN.1, DER serialization.
6
7import types
8
9
10def ToDER(obj):
11  '''ToDER converts the given object into DER encoding'''
12  if type(obj) == types.NoneType:
13    # None turns into NULL
14    return TagAndLength(5, 0)
15  if type(obj) == types.StringType:
16    # Strings are PRINTABLESTRING
17    return TagAndLength(19, len(obj)) + obj
18  if type(obj) == types.BooleanType:
19    val = "\x00"
20    if obj:
21      val = "\xff"
22    return TagAndLength(1, 1) + val
23  if type(obj) == types.IntType or type(obj) == types.LongType:
24    big_endian = []
25    val = obj
26    while val != 0:
27      big_endian.append(val & 0xff)
28      val >>= 8
29
30    if len(big_endian) == 0 or big_endian[-1] >= 128:
31      big_endian.append(0)
32
33    big_endian.reverse()
34    return TagAndLength(2, len(big_endian)) + ToBytes(big_endian)
35
36  return obj.ToDER()
37
38
39def ToBytes(array_of_bytes):
40  '''ToBytes converts the array of byte values into a binary string'''
41  return ''.join([chr(x) for x in array_of_bytes])
42
43
44def TagAndLength(tag, length):
45  der = [tag]
46  if length < 128:
47    der.append(length)
48  elif length < 256:
49    der.append(0x81)
50    der.append(length)
51  elif length < 65535:
52    der.append(0x82)
53    der.append(length >> 8)
54    der.append(length & 0xff)
55  else:
56    assert False
57
58  return ToBytes(der)
59
60
61class Raw(object):
62  '''Raw contains raw DER encoded bytes that are used verbatim'''
63  def __init__(self, der):
64    self.der = der
65
66  def ToDER(self):
67    return self.der
68
69
70class Explicit(object):
71  '''Explicit prepends an explicit tag'''
72  def __init__(self, tag, child):
73    self.tag = tag
74    self.child = child
75
76  def ToDER(self):
77    der = ToDER(self.child)
78    tag = self.tag
79    tag |= 0x80 # content specific
80    tag |= 0x20 # complex
81    return TagAndLength(tag, len(der)) + der
82
83
84class ENUMERATED(object):
85  def __init__(self, value):
86    self.value = value
87
88  def ToDER(self):
89    return TagAndLength(10, 1) + chr(self.value)
90
91
92class SEQUENCE(object):
93  def __init__(self, children):
94    self.children = children
95
96  def ToDER(self):
97    der = ''.join([ToDER(x) for x in self.children])
98    return TagAndLength(0x30, len(der)) + der
99
100
101class SET(object):
102  def __init__(self, children):
103    self.children = children
104
105  def ToDER(self):
106    der = ''.join([ToDER(x) for x in self.children])
107    return TagAndLength(0x31, len(der)) + der
108
109
110class OCTETSTRING(object):
111  def __init__(self, val):
112    self.val = val
113
114  def ToDER(self):
115    return TagAndLength(4, len(self.val)) + self.val
116
117
118class OID(object):
119  def __init__(self, parts):
120    self.parts = parts
121
122  def ToDER(self):
123    if len(self.parts) < 2 or self.parts[0] > 6 or self.parts[1] >= 40:
124      assert False
125
126    der = [self.parts[0]*40 + self.parts[1]]
127    for x in self.parts[2:]:
128      if x == 0:
129        der.append(0)
130      else:
131        octets = []
132        while x != 0:
133          v = x & 0x7f
134          if len(octets) > 0:
135            v |= 0x80
136          octets.append(v)
137          x >>= 7
138        octets.reverse()
139        der = der + octets
140
141    return TagAndLength(6, len(der)) + ToBytes(der)
142
143
144class UTCTime(object):
145  def __init__(self, time_str):
146    self.time_str = time_str
147
148  def ToDER(self):
149    return TagAndLength(23, len(self.time_str)) + self.time_str
150
151
152class GeneralizedTime(object):
153  def __init__(self, time_str):
154    self.time_str = time_str
155
156  def ToDER(self):
157    return TagAndLength(24, len(self.time_str)) + self.time_str
158
159
160class BitString(object):
161  def __init__(self, bits):
162    self.bits = bits
163
164  def ToDER(self):
165    return TagAndLength(3, 1 + len(self.bits)) + "\x00" + self.bits
166