diff options
-rw-r--r-- | CHANGELOG.rst | 3 | ||||
-rw-r--r-- | setup.py | 3 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/utils.py | 31 | ||||
-rw-r--r-- | src/cryptography/x509/extensions.py | 24 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_asym_utils.py | 3 | ||||
-rw-r--r-- | tests/test_x509.py | 21 |
6 files changed, 19 insertions, 66 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 744ec205..ee0a3455 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,9 @@ Changelog .. note:: This version is not yet released and is under active development. * Added support for Python 3.6. +* Changed ASN.1 dependency from ``pyasn1`` to ``asn1crypto`` resulting in a + general performance increase when encoding/decoding ASN.1 structures. Also, + the ``pyasn1_modules`` test dependency is no longer required. * Added :meth:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization.private_bytes` @@ -35,7 +35,7 @@ VECTORS_DEPENDENCY = "cryptography_vectors=={0}".format(about['__version__']) requirements = [ "idna>=2.0", - "pyasn1>=0.1.8", + "asn1crypto>=0.21.0", "six>=1.4.1", "setuptools>=11.3", ] @@ -61,7 +61,6 @@ test_requirements = [ "pytest>=2.9.0", "pretend", "iso8601", - "pyasn1_modules", "pytz", ] if sys.version_info[:2] > (2, 6): diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index 44bf59d1..4c2337bf 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py @@ -6,9 +6,7 @@ from __future__ import absolute_import, division, print_function import warnings -from pyasn1.codec.der import decoder, encoder -from pyasn1.error import PyAsn1Error -from pyasn1.type import namedtype, univ +from asn1crypto.algos import DSASignature import six @@ -16,13 +14,6 @@ from cryptography import utils from cryptography.hazmat.primitives import hashes -class _DSSSigValue(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('r', univ.Integer()), - namedtype.NamedType('s', univ.Integer()) - ) - - def decode_rfc6979_signature(signature): warnings.warn( "decode_rfc6979_signature is deprecated and will " @@ -34,19 +25,8 @@ def decode_rfc6979_signature(signature): def decode_dss_signature(signature): - try: - data, remaining = decoder.decode(signature, asn1Spec=_DSSSigValue()) - except PyAsn1Error: - raise ValueError("Invalid signature data. Unable to decode ASN.1") - - if remaining: - raise ValueError( - "The signature contains bytes after the end of the ASN.1 sequence." - ) - - r = int(data.getComponentByName('r')) - s = int(data.getComponentByName('s')) - return (r, s) + data = DSASignature.load(signature, strict=True).native + return data['r'], data['s'] def encode_rfc6979_signature(r, s): @@ -66,10 +46,7 @@ def encode_dss_signature(r, s): ): raise ValueError("Both r and s must be integers") - sig = _DSSSigValue() - sig.setComponentByName('r', r) - sig.setComponentByName('s', s) - return encoder.encode(sig) + return DSASignature({'r': r, 's': s}).dump() class Prehashed(object): diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index f7f6fcd3..1a3ced7d 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -11,8 +11,7 @@ import ipaddress import warnings from enum import Enum -from pyasn1.codec.der import decoder -from pyasn1.type import namedtype, univ +from asn1crypto.keys import PublicKeyInfo import six @@ -27,13 +26,6 @@ from cryptography.x509.oid import ( ) -class _SubjectPublicKeyInfo(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('algorithm', univ.Sequence()), - namedtype.NamedType('subjectPublicKey', univ.BitString()) - ) - - def _key_identifier_from_public_key(public_key): if isinstance(public_key, RSAPublicKey): data = public_key.public_bytes( @@ -48,18 +40,8 @@ def _key_identifier_from_public_key(public_key): serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo ) - spki, remaining = decoder.decode( - serialized, asn1Spec=_SubjectPublicKeyInfo() - ) - assert not remaining - # the univ.BitString object is a tuple of bits. We need bytes and - # pyasn1 really doesn't want to give them to us. To get it we'll - # build an integer and convert that to bytes. - bits = 0 - for bit in spki.getComponentByName("subjectPublicKey"): - bits = bits << 1 | bit - - data = utils.int_to_bytes(bits) + + data = six.binary_type(PublicKeyInfo.load(serialized)['public_key']) return hashlib.sha1(data).digest() diff --git a/tests/hazmat/primitives/test_asym_utils.py b/tests/hazmat/primitives/test_asym_utils.py index bd1fa35e..4835f091 100644 --- a/tests/hazmat/primitives/test_asym_utils.py +++ b/tests/hazmat/primitives/test_asym_utils.py @@ -73,8 +73,7 @@ def test_decode_dss_invalid_asn1(): decode_dss_signature(b"0\x07\x02\x01\x01\x02\x02\x01") with pytest.raises(ValueError): - # This is the BER "end-of-contents octets," which older versions of - # pyasn1 are wrongly willing to return from top-level DER decoding. + # This is the BER "end-of-contents octets". decode_dss_signature(b"\x00\x00") diff --git a/tests/test_x509.py b/tests/test_x509.py index 1ecf6b6a..db26f563 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -11,9 +11,7 @@ import os import sys import warnings -from pyasn1.codec.der import decoder - -from pyasn1_modules import rfc2459 +from asn1crypto.x509 import Certificate import pytest @@ -1458,17 +1456,12 @@ class TestRSACertificateRequest(object): cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - parsed, _ = decoder.decode( - cert.public_bytes(serialization.Encoding.DER), - asn1Spec=rfc2459.Certificate() - ) - tbs_cert = parsed.getComponentByName('tbsCertificate') - subject = tbs_cert.getComponentByName('subject') - issuer = tbs_cert.getComponentByName('issuer') - # \x13 is printable string. The first byte of the value of the - # node corresponds to the ASN.1 string type. - assert subject[0][0][0][1][0] == b"\x13"[0] - assert issuer[0][0][0][1][0] == b"\x13"[0] + parsed = Certificate.load( + cert.public_bytes(serialization.Encoding.DER)) + + # Check that each value was encoded as an ASN.1 PRINTABLESTRING. + assert parsed.subject.chosen[0][0]['value'].chosen.tag == 19 + assert parsed.issuer.chosen[0][0]['value'].chosen.tag == 19 class TestCertificateBuilder(object): |