blob: 358efbf342b1eda55ebf2d27aede8f16784ff666 [file] [log] [blame]
# 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)