# Copyright (c) 2012 The Chromium Authors. All rights reserved. # 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. import types def ToDER(obj): '''ToDER converts the given object into DER encoding''' if type(obj) == types.NoneType: # None turns into NULL return TagAndLength(5, 0) if type(obj) == types.StringType: # Strings are PRINTABLESTRING return TagAndLength(19, len(obj)) + obj if type(obj) == types.BooleanType: val = "\x00" if obj: val = "\xff" return TagAndLength(1, 1) + val if type(obj) == types.IntType or type(obj) == types.LongType: big_endian = [] 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 TagAndLength(2, len(big_endian)) + ToBytes(big_endian) return obj.ToDER() def ToBytes(array_of_bytes): '''ToBytes converts the array of byte values into a binary string''' return ''.join([chr(x) for x in array_of_bytes]) def TagAndLength(tag, length): der = [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 ToBytes(der) 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 TagAndLength(tag, len(der)) + der class ENUMERATED(object): def __init__(self, value): self.value = value def ToDER(self): return TagAndLength(10, 1) + chr(self.value) class SEQUENCE(object): def __init__(self, children): self.children = children def ToDER(self): der = ''.join([ToDER(x) for x in self.children]) return TagAndLength(0x30, len(der)) + der class SET(object): def __init__(self, children): self.children = children def ToDER(self): der = ''.join([ToDER(x) for x in self.children]) return TagAndLength(0x31, len(der)) + der class OCTETSTRING(object): def __init__(self, val): self.val = val def ToDER(self): return TagAndLength(4, len(self.val)) + 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 = [self.parts[0]*40 + self.parts[1]] for x in self.parts[2:]: if x == 0: der.append(0) else: octets = [] while x != 0: v = x & 0x7f if len(octets) > 0: v |= 0x80 octets.append(v) x >>= 7 octets.reverse() der = der + octets return TagAndLength(6, len(der)) + ToBytes(der) class UTCTime(object): def __init__(self, time_str): self.time_str = time_str def ToDER(self): return TagAndLength(23, len(self.time_str)) + self.time_str class GeneralizedTime(object): def __init__(self, time_str): self.time_str = time_str def ToDER(self): return TagAndLength(24, len(self.time_str)) + self.time_str class BitString(object): def __init__(self, bits): self.bits = bits def ToDER(self): return TagAndLength(3, 1 + len(self.bits)) + "\x00" + self.bits