# Copyright 2012 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # This file implements very minimal ASN.1, DER serialization. def ToDER(obj): '''ToDER converts the given object into DER encoding''' if obj is None: # None turns into NULL return TagAndLength(5, 0) if isinstance(obj, (str, bytes)): # There are many ASN.1 string types, so rather than pick one implicitly, # require the caller explicitly specify the encoding with asn1.UTF8String, # etc., below. raise TypeError("String types must be specified explicitly") if isinstance(obj, bool): val = b"\x00" if obj: val = b"\xff" return TagAndData(1, val) if isinstance(obj, int): big_endian = bytearray() val = obj while val != 0: big_endian.append(val & 0xff) val >>= 8 if len(big_endian) == 0 or big_endian[-1] >= 128: big_endian.append(0) big_endian.reverse() return TagAndData(2, bytes(big_endian)) return obj.ToDER() def TagAndLength(tag, length): der = bytearray([tag]) if length < 128: der.append(length) elif length < 256: der.append(0x81) der.append(length) elif length < 65535: der.append(0x82) der.append(length >> 8) der.append(length & 0xff) else: assert False return bytes(der) def TagAndData(tag, data): return TagAndLength(tag, len(data)) + data class Raw(object): '''Raw contains raw DER encoded bytes that are used verbatim''' def __init__(self, der): self.der = der def ToDER(self): return self.der class Explicit(object): '''Explicit prepends an explicit tag''' def __init__(self, tag, child): self.tag = tag self.child = child def ToDER(self): der = ToDER(self.child) tag = self.tag tag |= 0x80 # content specific tag |= 0x20 # complex return TagAndData(tag, der) class ENUMERATED(object): def __init__(self, value): self.value = value def ToDER(self): return TagAndData(10, bytes([self.value])) class SEQUENCE(object): def __init__(self, children): self.children = children def ToDER(self): der = b''.join([ToDER(x) for x in self.children]) return TagAndData(0x30, der) class SET(object): def __init__(self, children): self.children = children def ToDER(self): der = b''.join([ToDER(x) for x in self.children]) return TagAndData(0x31, der) class OCTETSTRING(object): def __init__(self, val): self.val = val def ToDER(self): return TagAndData(4, self.val) class PrintableString(object): def __init__(self, val): self.val = val def ToDER(self): return TagAndData(19, self.val) class UTF8String(object): def __init__(self, val): self.val = val def ToDER(self): return TagAndData(12, self.val) class OID(object): def __init__(self, parts): self.parts = parts def ToDER(self): if len(self.parts) < 2 or self.parts[0] > 6 or self.parts[1] >= 40: assert False der = bytearray([self.parts[0] * 40 + self.parts[1]]) for x in self.parts[2:]: if x == 0: der.append(0) else: octets = bytearray() while x != 0: v = x & 0x7f if len(octets) > 0: v |= 0x80 octets.append(v) x >>= 7 octets.reverse() der = der + octets return TagAndData(6, bytes(der)) class UTCTime(object): def __init__(self, time_str): self.time_str = time_str def ToDER(self): return TagAndData(23, self.time_str.encode('ascii')) class GeneralizedTime(object): def __init__(self, time_str): self.time_str = time_str def ToDER(self): return TagAndData(24, self.time_str.encode('ascii')) class BitString(object): def __init__(self, bits): self.bits = bits def ToDER(self): return TagAndData(3, b"\x00" + self.bits)