Correct crypto exception handling.

This commit is contained in:
William Grant
2011-03-12 17:19:59 +11:00
parent bafc0d5ea6
commit 440dd14de0
2 changed files with 41 additions and 11 deletions
+17 -1
View File
@@ -25,10 +25,12 @@ import time
import dns.resolver import dns.resolver
from dkim.crypto import ( from dkim.crypto import (
DigestTooLargeError,
parse_private_key, parse_private_key,
parse_public_key, parse_public_key,
RSASSA_PKCS1_v1_5_sign, RSASSA_PKCS1_v1_5_sign,
RSASSA_PKCS1_v1_5_verify, RSASSA_PKCS1_v1_5_verify,
UnparsableKeyError,
) )
from dkim.util import ( from dkim.util import (
InvalidTagValueList, InvalidTagValueList,
@@ -273,7 +275,11 @@ def sign(message, selector, domain, privkey, identity=None, canonicalize=(Simple
raise KeyFormatError(str(e)) raise KeyFormatError(str(e))
if debuglog is not None: if debuglog is not None:
print >>debuglog, " ".join("%02x" % ord(x) for x in pkdata) print >>debuglog, " ".join("%02x" % ord(x) for x in pkdata)
try:
pk = parse_private_key(pkdata) pk = parse_private_key(pkdata)
except UnparsableKeyError, e:
raise KeyFormatError(str(e))
if identity is not None and not identity.endswith(domain): if identity is not None and not identity.endswith(domain):
raise ParameterError("identity must end with domain") raise ParameterError("identity must end with domain")
@@ -321,8 +327,11 @@ def sign(message, selector, domain, privkey, identity=None, canonicalize=(Simple
if debuglog is not None: if debuglog is not None:
print >>debuglog, "sign digest:", " ".join("%02x" % ord(x) for x in d) print >>debuglog, "sign digest:", " ".join("%02x" % ord(x) for x in d)
try:
sig2 = RSASSA_PKCS1_v1_5_sign( sig2 = RSASSA_PKCS1_v1_5_sign(
d, HASHID_SHA256, pk['privateExponent'], pk['modulus']) d, HASHID_SHA256, pk['privateExponent'], pk['modulus'])
except DigestTooLargeError:
raise ParameterError("digest too large for modulus")
sig += base64.b64encode(sig2) sig += base64.b64encode(sig2)
return sig + "\r\n" return sig + "\r\n"
@@ -414,7 +423,12 @@ def verify(message, debuglog=None, dnsfunc=dnstxt):
pub = parse_tag_value(s) pub = parse_tag_value(s)
except InvalidTagValueList: except InvalidTagValueList:
return False return False
try:
pk = parse_public_key(base64.b64decode(pub['p'])) pk = parse_public_key(base64.b64decode(pub['p']))
except UnparsableKeyError, e:
if debuglog is not None:
print >>debuglog, "could not parse public key: %s" % e
return False
include_headers = re.split(r"\s*:\s*", sig['h']) include_headers = re.split(r"\s*:\s*", sig['h'])
h = hasher() h = hasher()
@@ -427,5 +441,7 @@ def verify(message, debuglog=None, dnsfunc=dnstxt):
try: try:
return RSASSA_PKCS1_v1_5_verify( return RSASSA_PKCS1_v1_5_verify(
d, hashid, signature, pk['publicExponent'], pk['modulus']) d, hashid, signature, pk['publicExponent'], pk['modulus'])
except ParameterError: except DigestTooLargeError:
if debuglog is not None:
print >>debuglog, "digest too large for modulus"
return False return False
+17 -3
View File
@@ -18,13 +18,16 @@
# Copyright (c) 2011 William Grant <me@williamgrant.id.au> # Copyright (c) 2011 William Grant <me@williamgrant.id.au>
__all__ = [ __all__ = [
'DigestTooLargeError',
'parse_private_key', 'parse_private_key',
'parse_public_key', 'parse_public_key',
'RSASSA_PKCS1_v1_5_sign', 'RSASSA_PKCS1_v1_5_sign',
'RSASSA_PKCS1_v1_5_verify', 'RSASSA_PKCS1_v1_5_verify',
'UnparsableKeyError',
] ]
from dkim.asn1 import ( from dkim.asn1 import (
ASN1FormatError,
asn1_build, asn1_build,
asn1_parse, asn1_parse,
BIT_STRING, BIT_STRING,
@@ -68,11 +71,16 @@ ASN1_RSAPrivateKey = [
] ]
class DigestTooLarge(Exception): class DigestTooLargeError(Exception):
"""The digest is too large to fit within the requested length.""" """The digest is too large to fit within the requested length."""
pass pass
class UnparsableKeyError(Exception):
"""The data could not be parsed as a key."""
pass
def parse_public_key(data): def parse_public_key(data):
"""Parse an RSA public key. """Parse an RSA public key.
@@ -80,9 +88,12 @@ def parse_public_key(data):
containing an RFC3447 RSAPublicKey. containing an RFC3447 RSAPublicKey.
@return: RSA public key @return: RSA public key
""" """
x = asn1_parse(ASN1_Object, data) try:
# Not sure why the [1:] is necessary to skip a byte. # Not sure why the [1:] is necessary to skip a byte.
x = asn1_parse(ASN1_Object, data)
pkd = asn1_parse(ASN1_RSAPublicKey, x[0][1][1:]) pkd = asn1_parse(ASN1_RSAPublicKey, x[0][1][1:])
except ASN1FormatError, e:
raise UnparsableKeyError(str(e))
pk = { pk = {
'modulus': pkd[0][0], 'modulus': pkd[0][0],
'publicExponent': pkd[0][1], 'publicExponent': pkd[0][1],
@@ -96,7 +107,10 @@ def parse_private_key(data):
@param data: DER-encoded RFC3447 RSAPrivateKey. @param data: DER-encoded RFC3447 RSAPrivateKey.
@return: RSA private key @return: RSA private key
""" """
try:
pka = asn1_parse(ASN1_RSAPrivateKey, data) pka = asn1_parse(ASN1_RSAPrivateKey, data)
except ASN1FormatError, e:
raise UnparsableKeyError(str(e))
pk = { pk = {
'version': pka[0][0], 'version': pka[0][0],
'modulus': pka[0][1], 'modulus': pka[0][1],
@@ -128,7 +142,7 @@ def EMSA_PKCS1_v1_5_encode(digest, mlen, hashid):
(OCTET_STRING, digest), (OCTET_STRING, digest),
])) ]))
if len(dinfo)+3 > mlen: if len(dinfo)+3 > mlen:
raise DigestTooLarge() raise DigestTooLargeError()
return "\x00\x01"+"\xff"*(mlen-len(dinfo)-3)+"\x00"+dinfo return "\x00\x01"+"\xff"*(mlen-len(dinfo)-3)+"\x00"+dinfo