Split ASN.1 utilities out into their own file.

This commit is contained in:
William Grant
2011-03-09 23:23:01 +11:00
parent b3225a0a24
commit b6d3502f9e
2 changed files with 130 additions and 99 deletions
+11 -99
View File
@@ -1,21 +1,3 @@
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the author be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
#
# Copyright (c) 2008 Greg Hewgill http://hewgill.com
import base64
import hashlib
import re
@@ -23,6 +5,17 @@ import time
import dns.resolver
from dkim.asn1 import (
asn1_build,
asn1_parse,
BIT_STRING,
INTEGER,
SEQUENCE,
OBJECT_IDENTIFIER,
OCTET_STRING,
NULL,
)
__all__ = [
"Simple",
"Relaxed",
@@ -208,13 +201,6 @@ def validate_signature_fields(sig, debuglog=None):
return True
INTEGER = 0x02
BIT_STRING = 0x03
OCTET_STRING = 0x04
NULL = 0x05
OBJECT_IDENTIFIER = 0x06
SEQUENCE = 0x30
ASN1_Object = [
(SEQUENCE, [
(SEQUENCE, [
@@ -246,80 +232,6 @@ ASN1_RSAPrivateKey = [
])
]
def asn1_parse(template, data):
"""Parse a data structure according to ASN.1 template.
@param template: A list of tuples comprising the ASN.1 template.
@param data: A list of bytes to parse.
"""
r = []
i = 0
for t in template:
tag = ord(data[i])
i += 1
if tag == t[0]:
length = ord(data[i])
i += 1
if length & 0x80:
n = length & 0x7f
length = 0
for j in range(n):
length = (length << 8) | ord(data[i])
i += 1
if tag == INTEGER:
n = 0
for j in range(length):
n = (n << 8) | ord(data[i])
i += 1
r.append(n)
elif tag == BIT_STRING:
r.append(data[i:i+length])
i += length
elif tag == NULL:
assert length == 0
r.append(None)
elif tag == OBJECT_IDENTIFIER:
r.append(data[i:i+length])
i += length
elif tag == SEQUENCE:
r.append(asn1_parse(t[1], data[i:i+length]))
i += length
else:
raise KeyFormatError("Unexpected tag in template: %02x" % tag)
else:
raise KeyFormatError("Unexpected tag (got %02x, expecting %02x)" % (tag, t[0]))
return r
def asn1_length(n):
"""Return a string representing a field length in ASN.1 format."""
assert n >= 0
if n < 0x7f:
return chr(n)
r = ""
while n > 0:
r = chr(n & 0xff) + r
n >>= 8
return r
def asn1_build(node):
"""Build an ASN.1 data structure based on pairs of (type, data)."""
if node[0] == OCTET_STRING:
return chr(OCTET_STRING) + asn1_length(len(node[1])) + node[1]
if node[0] == NULL:
assert node[1] is None
return chr(NULL) + asn1_length(0)
elif node[0] == OBJECT_IDENTIFIER:
return chr(OBJECT_IDENTIFIER) + asn1_length(len(node[1])) + node[1]
elif node[0] == SEQUENCE:
r = ""
for x in node[1]:
r += asn1_build(x)
return chr(SEQUENCE) + asn1_length(len(r)) + r
else:
raise InternalError("Unexpected tag in template: %02x" % node[0])
# These values come from RFC 3447, section 9.2 Notes, page 43.
HASHID_SHA1 = "\x2b\x0e\x03\x02\x1a"
HASHID_SHA256 = "\x60\x86\x48\x01\x65\x03\x04\x02\x01"
+119
View File
@@ -0,0 +1,119 @@
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the author be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
#
# Copyright (c) 2008 Greg Hewgill http://hewgill.com
__all__ = [
'asn1_build',
'asn1_parse',
'ASN1FormatError',
'BIT_STRING',
'INTEGER',
'SEQUENCE',
'OBJECT_IDENTIFIER',
'OCTET_STRING',
'NULL',
]
INTEGER = 0x02
BIT_STRING = 0x03
OCTET_STRING = 0x04
NULL = 0x05
OBJECT_IDENTIFIER = 0x06
SEQUENCE = 0x30
class ASN1FormatError(Exception):
pass
def asn1_parse(template, data):
"""Parse a data structure according to ASN.1 template.
@param template: A list of tuples comprising the ASN.1 template.
@param data: A list of bytes to parse.
"""
r = []
i = 0
for t in template:
tag = ord(data[i])
i += 1
if tag == t[0]:
length = ord(data[i])
i += 1
if length & 0x80:
n = length & 0x7f
length = 0
for j in range(n):
length = (length << 8) | ord(data[i])
i += 1
if tag == INTEGER:
n = 0
for j in range(length):
n = (n << 8) | ord(data[i])
i += 1
r.append(n)
elif tag == BIT_STRING:
r.append(data[i:i+length])
i += length
elif tag == NULL:
assert length == 0
r.append(None)
elif tag == OBJECT_IDENTIFIER:
r.append(data[i:i+length])
i += length
elif tag == SEQUENCE:
r.append(asn1_parse(t[1], data[i:i+length]))
i += length
else:
raise ASN1FormatError(
"Unexpected tag in template: %02x" % tag)
else:
raise ASN1FormatError(
"Unexpected tag (got %02x, expecting %02x)" % (tag, t[0]))
return r
def asn1_length(n):
"""Return a string representing a field length in ASN.1 format."""
assert n >= 0
if n < 0x7f:
return chr(n)
r = ""
while n > 0:
r = chr(n & 0xff) + r
n >>= 8
return r
def asn1_build(node):
"""Build an ASN.1 data structure based on pairs of (type, data)."""
if node[0] == OCTET_STRING:
return chr(OCTET_STRING) + asn1_length(len(node[1])) + node[1]
if node[0] == NULL:
assert node[1] is None
return chr(NULL) + asn1_length(0)
elif node[0] == OBJECT_IDENTIFIER:
return chr(OBJECT_IDENTIFIER) + asn1_length(len(node[1])) + node[1]
elif node[0] == SEQUENCE:
r = ""
for x in node[1]:
r += asn1_build(x)
return chr(SEQUENCE) + asn1_length(len(r)) + r
else:
raise ASN1FormatError("Unexpected tag in template: %02x" % node[0])