# 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