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