зеркало из https://github.com/mozilla/gecko-dev.git
bug 1360623 - add hash algorithm constants to pykey for easier consumer use r=jcj
For signing, pykey.py delegates to 3rd party libraries. One of these libraries expects hash algorithms to be specified in the form "SHA-256" whereas the other expects "sha256". Consumers of pykey shouldn't need to be aware of this detail. This patch introduces constants HASH_SHA1, HASH_SHA256, etc. and changes pykey to determine which string literals to use itself. MozReview-Commit-ID: 27laM2uXMwJ --HG-- extra : rebase_source : 9b74f486f7535671fd26c59e3e9cc3b4459f15e0
This commit is contained in:
Родитель
7d8e567c4c
Коммит
1ef3597000
|
@ -303,26 +303,26 @@ def stringToDN(string, tag=None):
|
|||
def stringToAlgorithmIdentifiers(string):
|
||||
"""Helper function that converts a description of an algorithm
|
||||
to a representation usable by the pyasn1 package and a hash
|
||||
algorithm name for use by pykey."""
|
||||
algorithm constant for use by pykey."""
|
||||
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||
algorithmName = None
|
||||
algorithmType = None
|
||||
algorithm = None
|
||||
if string == 'sha1WithRSAEncryption':
|
||||
algorithmName = 'SHA-1'
|
||||
algorithmType = pykey.HASH_SHA1
|
||||
algorithm = rfc2459.sha1WithRSAEncryption
|
||||
elif string == 'sha256WithRSAEncryption':
|
||||
algorithmName = 'SHA-256'
|
||||
algorithmType = pykey.HASH_SHA256
|
||||
algorithm = univ.ObjectIdentifier('1.2.840.113549.1.1.11')
|
||||
elif string == 'md5WithRSAEncryption':
|
||||
algorithmName = 'MD5'
|
||||
algorithmType = pykey.HASH_MD5
|
||||
algorithm = rfc2459.md5WithRSAEncryption
|
||||
elif string == 'ecdsaWithSHA256':
|
||||
algorithmName = 'sha256'
|
||||
algorithmType = pykey.HASH_SHA256
|
||||
algorithm = univ.ObjectIdentifier('1.2.840.10045.4.3.2')
|
||||
else:
|
||||
raise UnknownAlgorithmTypeError(string)
|
||||
algorithmIdentifier.setComponentByName('algorithm', algorithm)
|
||||
return (algorithmIdentifier, algorithmName)
|
||||
return (algorithmIdentifier, algorithmType)
|
||||
|
||||
def datetimeToTime(dt):
|
||||
"""Takes a datetime object and returns an rfc2459.Time object with
|
||||
|
@ -640,7 +640,7 @@ class Certificate(object):
|
|||
return stringToDN(self.subject)
|
||||
|
||||
def toDER(self):
|
||||
(signatureOID, hashName) = stringToAlgorithmIdentifiers(self.signature)
|
||||
(signatureOID, hashAlgorithm) = stringToAlgorithmIdentifiers(self.signature)
|
||||
tbsCertificate = rfc2459.TBSCertificate()
|
||||
tbsCertificate.setComponentByName('version', self.getVersion())
|
||||
tbsCertificate.setComponentByName('serialNumber', self.getSerialNumber())
|
||||
|
@ -660,7 +660,7 @@ class Certificate(object):
|
|||
certificate.setComponentByName('tbsCertificate', tbsCertificate)
|
||||
certificate.setComponentByName('signatureAlgorithm', signatureOID)
|
||||
tbsDER = encoder.encode(tbsCertificate)
|
||||
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER, hashName))
|
||||
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER, hashAlgorithm))
|
||||
return encoder.encode(certificate)
|
||||
|
||||
def toPEM(self):
|
||||
|
|
|
@ -41,6 +41,11 @@ import mock
|
|||
import rsa
|
||||
import sys
|
||||
|
||||
# "constants" to make it easier for consumers to specify hash algorithms
|
||||
HASH_MD5 = 'hash:md5'
|
||||
HASH_SHA1 = 'hash:sha1'
|
||||
HASH_SHA256 = 'hash:sha256'
|
||||
|
||||
def byteStringToHexifiedBitString(string):
|
||||
"""Takes a string of bytes and returns a hex string representing
|
||||
those bytes for use with pyasn1.type.univ.BitString. It must be of
|
||||
|
@ -66,6 +71,25 @@ class UnknownKeySpecificationError(UnknownBaseError):
|
|||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'key specification'
|
||||
|
||||
|
||||
class UnknownHashAlgorithmError(UnknownBaseError):
|
||||
"""Helper exception type to handle unknown key specifications."""
|
||||
|
||||
def __init__(self, value):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'hash algorithm'
|
||||
|
||||
|
||||
class UnsupportedHashAlgorithmError(Exception):
|
||||
"""Helper exception type for unsupported hash algorithms."""
|
||||
def __init__(self, value):
|
||||
super(UnsupportedHashAlgorithmError, self).__init__()
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return 'Unsupported hash algorithm "%s"' % repr(self.value)
|
||||
|
||||
|
||||
class RSAPublicKey(univ.Sequence):
|
||||
"""Helper type for encoding an RSA public key"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
|
@ -553,10 +577,19 @@ class RSAKey(object):
|
|||
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
|
||||
return spki
|
||||
|
||||
def sign(self, data, hashAlgorithmName):
|
||||
def sign(self, data, hashAlgorithm):
|
||||
"""Returns a hexified bit string representing a
|
||||
signature by this key over the specified data.
|
||||
Intended for use with pyasn1.type.univ.BitString"""
|
||||
hashAlgorithmName = None
|
||||
if hashAlgorithm == HASH_MD5:
|
||||
hashAlgorithmName = "MD5"
|
||||
elif hashAlgorithm == HASH_SHA1:
|
||||
hashAlgorithmName = "SHA-1"
|
||||
elif hashAlgorithm == HASH_SHA256:
|
||||
hashAlgorithmName = "SHA-256"
|
||||
else:
|
||||
raise UnknownHashAlgorithmError(hashAlgorithm)
|
||||
rsaPrivateKey = rsa.PrivateKey(self.RSA_N, self.RSA_E, self.RSA_D, self.RSA_P, self.RSA_Q)
|
||||
signature = rsa.sign(data, rsaPrivateKey, hashAlgorithmName)
|
||||
return byteStringToHexifiedBitString(signature)
|
||||
|
@ -664,10 +697,12 @@ class ECCKey(object):
|
|||
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
|
||||
return spki
|
||||
|
||||
def sign(self, data, hashAlgorithmName):
|
||||
def sign(self, data, hashAlgorithm):
|
||||
"""Returns a hexified bit string representing a
|
||||
signature by this key over the specified data.
|
||||
Intended for use with pyasn1.type.univ.BitString"""
|
||||
if hashAlgorithm != HASH_SHA256:
|
||||
raise UnsupportedHashAlgorithmError(hashAlgorithm)
|
||||
# There is some non-determinism in ECDSA signatures. Work around
|
||||
# this by patching ecc.ecdsa.urandom to not be random.
|
||||
with mock.patch('ecc.ecdsa.urandom', side_effect=notRandom):
|
||||
|
@ -677,9 +712,9 @@ class ECCKey(object):
|
|||
# Also patch in secp256k1 if applicable.
|
||||
if self.keyOID == secp256k1:
|
||||
with mock.patch('ecc.curves.DOMAINS', {256: secp256k1Params}):
|
||||
x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
|
||||
x, y = encoding.dec_point(self.key.sign(data, 'sha256'))
|
||||
else:
|
||||
x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
|
||||
x, y = encoding.dec_point(self.key.sign(data, 'sha256'))
|
||||
point = ECPoint()
|
||||
point.setComponentByName('x', x)
|
||||
point.setComponentByName('y', y)
|
||||
|
|
Загрузка…
Ссылка в новой задаче