183 lines
3.8 KiB
Python
183 lines
3.8 KiB
Python
# 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)
|