summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLegrandin <helderijs@gmail.com>2013-02-15 09:21:22 +0100
committerDwayne Litzenberger <dlitz@dlitz.net>2013-07-14 23:07:48 -0700
commit546c192d61ad3494433281432c0274ef6d638466 (patch)
tree327a71e16fc73d3d4e8b3b190ee7cfbc297b03b9
parentd7cc92168a1cb0cac0f3e13a6160497c5770767e (diff)
downloadpycrypto-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.py41
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(),