blob: 167b08d3ce9faa3e0eefb153f6653cad0f54d4de [file] [log] [blame]
agl@chromium.org77a9ad92012-03-20 15:14:27 +00001# 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
Matt Mueller8270eb82019-05-04 00:37:24 +000018 if type(obj) == types.UnicodeType:
19 # Encode Unicode strings as UTF8String.
20 utf8val = obj.encode('utf-8')
21 return TagAndLength(12, len(utf8val)) + utf8val
agl@chromium.org77a9ad92012-03-20 15:14:27 +000022 if type(obj) == types.BooleanType:
23 val = "\x00"
24 if obj:
25 val = "\xff"
26 return TagAndLength(1, 1) + val
27 if type(obj) == types.IntType or type(obj) == types.LongType:
28 big_endian = []
29 val = obj
30 while val != 0:
31 big_endian.append(val & 0xff)
32 val >>= 8
33
34 if len(big_endian) == 0 or big_endian[-1] >= 128:
35 big_endian.append(0)
36
37 big_endian.reverse()
38 return TagAndLength(2, len(big_endian)) + ToBytes(big_endian)
39
40 return obj.ToDER()
41
42
43def ToBytes(array_of_bytes):
44 '''ToBytes converts the array of byte values into a binary string'''
45 return ''.join([chr(x) for x in array_of_bytes])
46
47
48def TagAndLength(tag, length):
49 der = [tag]
50 if length < 128:
51 der.append(length)
52 elif length < 256:
53 der.append(0x81)
54 der.append(length)
55 elif length < 65535:
56 der.append(0x82)
57 der.append(length >> 8)
58 der.append(length & 0xff)
59 else:
60 assert False
61
62 return ToBytes(der)
63
64
65class Raw(object):
66 '''Raw contains raw DER encoded bytes that are used verbatim'''
67 def __init__(self, der):
68 self.der = der
69
70 def ToDER(self):
71 return self.der
72
73
74class Explicit(object):
75 '''Explicit prepends an explicit tag'''
76 def __init__(self, tag, child):
77 self.tag = tag
78 self.child = child
79
80 def ToDER(self):
81 der = ToDER(self.child)
82 tag = self.tag
83 tag |= 0x80 # content specific
84 tag |= 0x20 # complex
85 return TagAndLength(tag, len(der)) + der
86
87
88class ENUMERATED(object):
89 def __init__(self, value):
90 self.value = value
91
92 def ToDER(self):
93 return TagAndLength(10, 1) + chr(self.value)
94
95
96class SEQUENCE(object):
97 def __init__(self, children):
98 self.children = children
99
100 def ToDER(self):
101 der = ''.join([ToDER(x) for x in self.children])
102 return TagAndLength(0x30, len(der)) + der
103
104
105class SET(object):
106 def __init__(self, children):
107 self.children = children
108
109 def ToDER(self):
110 der = ''.join([ToDER(x) for x in self.children])
111 return TagAndLength(0x31, len(der)) + der
112
113
114class OCTETSTRING(object):
115 def __init__(self, val):
116 self.val = val
117
118 def ToDER(self):
119 return TagAndLength(4, len(self.val)) + self.val
120
121
122class OID(object):
123 def __init__(self, parts):
124 self.parts = parts
125
126 def ToDER(self):
127 if len(self.parts) < 2 or self.parts[0] > 6 or self.parts[1] >= 40:
128 assert False
129
130 der = [self.parts[0]*40 + self.parts[1]]
131 for x in self.parts[2:]:
132 if x == 0:
133 der.append(0)
134 else:
135 octets = []
136 while x != 0:
137 v = x & 0x7f
138 if len(octets) > 0:
139 v |= 0x80
140 octets.append(v)
141 x >>= 7
142 octets.reverse()
143 der = der + octets
144
145 return TagAndLength(6, len(der)) + ToBytes(der)
146
147
148class UTCTime(object):
149 def __init__(self, time_str):
150 self.time_str = time_str
151
152 def ToDER(self):
153 return TagAndLength(23, len(self.time_str)) + self.time_str
154
155
156class GeneralizedTime(object):
157 def __init__(self, time_str):
158 self.time_str = time_str
159
160 def ToDER(self):
161 return TagAndLength(24, len(self.time_str)) + self.time_str
162
163
164class BitString(object):
165 def __init__(self, bits):
166 self.bits = bits
167
168 def ToDER(self):
169 return TagAndLength(3, 1 + len(self.bits)) + "\x00" + self.bits