diff options
author | Legrandin <helderijs@gmail.com> | 2013-02-15 09:21:22 +0100 |
---|---|---|
committer | Dwayne Litzenberger <dlitz@dlitz.net> | 2013-07-14 23:07:48 -0700 |
commit | 546c192d61ad3494433281432c0274ef6d638466 (patch) | |
tree | 327a71e16fc73d3d4e8b3b190ee7cfbc297b03b9 | |
parent | d7cc92168a1cb0cac0f3e13a6160497c5770767e (diff) | |
download | pycrypto-546c192d61ad3494433281432c0274ef6d638466.tar.gz |
Bugfix #1119552: PKCS#1v1.5 has to accept signatures without NULL parameters
The digest AlgorithmIdentifier has optional (NULL) parameters; the
verification function should not reject a signature if they are omitted.
With this fix, either case is acceptable (parameters present with value NULL
or not present).
As an exception, signatures based on old MD2/MD5 must always have NULL
parameters.
See Appendix B.1 of RFC 3447 and Section 2.1 of RFC 4055.
Closes: https://bugs.launchpad.net/pycrypto/+bug/1119552
[dlitz: Rebased and updated to use refactored asn1 API, text OIDs, & to fix Python 2.1.]
-rw-r--r-- | lib/Crypto/Signature/PKCS1_v1_5.py | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/lib/Crypto/Signature/PKCS1_v1_5.py b/lib/Crypto/Signature/PKCS1_v1_5.py index be48aee..4ea1224 100644 --- a/lib/Crypto/Signature/PKCS1_v1_5.py +++ b/lib/Crypto/Signature/PKCS1_v1_5.py @@ -60,9 +60,13 @@ the RSA key: __revision__ = "$Id$" __all__ = [ 'new', 'PKCS115_SigScheme' ] +import sys + import Crypto.Util.number from Crypto.Util.number import ceil_div from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId +if sys.version_info[0] == 2 and sys.version_info[1] == 1: + from Crypto.Util.py21compat import * from Crypto.Util.py3compat import * class PKCS115_SigScheme: @@ -150,7 +154,13 @@ class PKCS115_SigScheme: em1 = bchr(0x00)*(k-len(m)) + m # Step 3 try: - em2 = EMSA_PKCS1_V1_5_ENCODE(mhash, k) + em2_with_params = EMSA_PKCS1_V1_5_ENCODE(mhash, k, True) + # MD hashes always require NULL params in AlgorithmIdentifier. + # For all others, it is optional. + if _HASH_OIDS[mhash.name].startswith('1.2.840.113549.2.'): # MD2/MD4/MD5 + em2_without_params = em2_with_params + else: + em2_without_params = EMSA_PKCS1_V1_5_ENCODE(mhash, k, False) except ValueError: return 0 # Step 4 @@ -158,9 +168,9 @@ class PKCS115_SigScheme: # of its components one at a time) we avoid attacks to the padding # scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537). # - return em1==em2 + return em1==em2_with_params or em1==em2_without_params -def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): +def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True): """ Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.2). @@ -174,6 +184,9 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): The hash object that holds the digest of the message being signed. emLen : int The length the final encoding must have, in bytes. + with_hash_parameters: + If True (default), include NULL parameters for the hash + algorithm in the ``digestAlgorithm`` SEQUENCE. :attention: the early standard (RFC2313) stated that ``DigestInfo`` had to be BER-encoded. This means that old signatures @@ -181,11 +194,6 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): is not supported in DER. Such encoding cannot be reproduced by this function. - :attention: the same standard defined ``DigestAlgorithm`` to be - of ``AlgorithmIdentifier`` type, where the PARAMETERS - item is optional. Encodings for ``MD2/4/5`` without - ``PARAMETERS`` cannot be reproduced by this function. - :Return: An ``emLen`` byte long string that encodes the hash. """ @@ -208,10 +216,19 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): # { OID id-sha512 PARAMETERS NULL } # } # - digestAlgo = DerSequence([ - DerObjectId(_HASH_OIDS[hash.name]).encode(), - DerNull().encode() - ]) + # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters + # should be omitted. They may be present, but when they are, they shall + # have NULL value. + + if with_hash_parameters: + digestAlgo = DerSequence([ + DerObjectId(_HASH_OIDS[hash.name]).encode(), + DerNull().encode() + ]) + else: + digestAlgo = DerSequence([ + DerObjectId(_HASH_OIDS[hash.name]).encode(), + ]) digest = DerOctetString(hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), |