xref: /aosp_15_r20/external/cronet/net/data/ssl/scripts/asn1.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Copyright 2012 The Chromium Authors
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
7
8def ToDER(obj):
9  '''ToDER converts the given object into DER encoding'''
10  if obj is None:
11    # None turns into NULL
12    return TagAndLength(5, 0)
13  if isinstance(obj, (str, bytes)):
14    # There are many ASN.1 string types, so rather than pick one implicitly,
15    # require the caller explicitly specify the encoding with asn1.UTF8String,
16    # etc., below.
17    raise TypeError("String types must be specified explicitly")
18  if isinstance(obj, bool):
19    val = b"\x00"
20    if obj:
21      val = b"\xff"
22    return TagAndData(1, val)
23  if isinstance(obj, int):
24    big_endian = bytearray()
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 TagAndData(2, bytes(big_endian))
35
36  return obj.ToDER()
37
38
39def TagAndLength(tag, length):
40  der = bytearray([tag])
41  if length < 128:
42    der.append(length)
43  elif length < 256:
44    der.append(0x81)
45    der.append(length)
46  elif length < 65535:
47    der.append(0x82)
48    der.append(length >> 8)
49    der.append(length & 0xff)
50  else:
51    assert False
52
53  return bytes(der)
54
55
56def TagAndData(tag, data):
57  return TagAndLength(tag, len(data)) + data
58
59
60class Raw(object):
61  '''Raw contains raw DER encoded bytes that are used verbatim'''
62
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
73  def __init__(self, tag, child):
74    self.tag = tag
75    self.child = child
76
77  def ToDER(self):
78    der = ToDER(self.child)
79    tag = self.tag
80    tag |= 0x80  # content specific
81    tag |= 0x20  # complex
82    return TagAndData(tag, der)
83
84
85class ENUMERATED(object):
86  def __init__(self, value):
87    self.value = value
88
89  def ToDER(self):
90    return TagAndData(10, bytes([self.value]))
91
92
93class SEQUENCE(object):
94  def __init__(self, children):
95    self.children = children
96
97  def ToDER(self):
98    der = b''.join([ToDER(x) for x in self.children])
99    return TagAndData(0x30, der)
100
101
102class SET(object):
103  def __init__(self, children):
104    self.children = children
105
106  def ToDER(self):
107    der = b''.join([ToDER(x) for x in self.children])
108    return TagAndData(0x31, der)
109
110
111class OCTETSTRING(object):
112  def __init__(self, val):
113    self.val = val
114
115  def ToDER(self):
116    return TagAndData(4, self.val)
117
118
119class PrintableString(object):
120  def __init__(self, val):
121    self.val = val
122
123  def ToDER(self):
124    return TagAndData(19, self.val)
125
126
127class UTF8String(object):
128  def __init__(self, val):
129    self.val = val
130
131  def ToDER(self):
132    return TagAndData(12, self.val)
133
134
135class OID(object):
136  def __init__(self, parts):
137    self.parts = parts
138
139  def ToDER(self):
140    if len(self.parts) < 2 or self.parts[0] > 6 or self.parts[1] >= 40:
141      assert False
142
143    der = bytearray([self.parts[0] * 40 + self.parts[1]])
144    for x in self.parts[2:]:
145      if x == 0:
146        der.append(0)
147      else:
148        octets = bytearray()
149        while x != 0:
150          v = x & 0x7f
151          if len(octets) > 0:
152            v |= 0x80
153          octets.append(v)
154          x >>= 7
155        octets.reverse()
156        der = der + octets
157
158    return TagAndData(6, bytes(der))
159
160
161class UTCTime(object):
162  def __init__(self, time_str):
163    self.time_str = time_str
164
165  def ToDER(self):
166    return TagAndData(23, self.time_str.encode('ascii'))
167
168
169class GeneralizedTime(object):
170  def __init__(self, time_str):
171    self.time_str = time_str
172
173  def ToDER(self):
174    return TagAndData(24, self.time_str.encode('ascii'))
175
176
177class BitString(object):
178  def __init__(self, bits):
179    self.bits = bits
180
181  def ToDER(self):
182    return TagAndData(3, b"\x00" + self.bits)
183