From 44ef438869f80fae640c34ab8689d8108b7ef27c Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 14:18:37 +0200 Subject: [PATCH 1/4] add missing SECP256k1 to __all__ the curve is oficially supported, add it to star import --- src/ecdsa/curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ecdsa/curves.py b/src/ecdsa/curves.py index b61f4b45..d0874e64 100644 --- a/src/ecdsa/curves.py +++ b/src/ecdsa/curves.py @@ -8,7 +8,7 @@ # will need to mark it as deprecated later __all__ = ["UnknownCurveError", "orderlen", "Curve", "NIST192p", "NIST224p", "NIST256p", "NIST384p", "NIST521p", "curves", - "find_curve"] + "find_curve", "SECP256k1"] class UnknownCurveError(Exception): From d970ed1c40e3b051ff13f1f59fe7e7b267d72953 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 14:19:45 +0200 Subject: [PATCH 2/4] curves: add repr() support for easier diagnostics with hypothesis, it's nice to have the curves named also fix formatting in the module --- src/ecdsa/curves.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ecdsa/curves.py b/src/ecdsa/curves.py index d0874e64..2555d938 100644 --- a/src/ecdsa/curves.py +++ b/src/ecdsa/curves.py @@ -15,7 +15,6 @@ class UnknownCurveError(Exception): pass -# the NIST curves class Curve: def __init__(self, name, curve, generator, oid, openssl_name=None): self.name = name @@ -29,25 +28,41 @@ def __init__(self, name, curve, generator, oid, openssl_name=None): self.oid = oid self.encoded_oid = der.encode_oid(*oid) + def __repr__(self): + return self.name + + +# the NIST curves NIST192p = Curve("NIST192p", ecdsa.curve_192, ecdsa.generator_192, (1, 2, 840, 10045, 3, 1, 1), "prime192v1") + + NIST224p = Curve("NIST224p", ecdsa.curve_224, ecdsa.generator_224, (1, 3, 132, 0, 33), "secp224r1") + + NIST256p = Curve("NIST256p", ecdsa.curve_256, ecdsa.generator_256, (1, 2, 840, 10045, 3, 1, 7), "prime256v1") + + NIST384p = Curve("NIST384p", ecdsa.curve_384, ecdsa.generator_384, (1, 3, 132, 0, 34), "secp384r1") + + NIST521p = Curve("NIST521p", ecdsa.curve_521, ecdsa.generator_521, (1, 3, 132, 0, 35), "secp521r1") + + SECP256k1 = Curve("SECP256k1", ecdsa.curve_secp256k1, ecdsa.generator_secp256k1, (1, 3, 132, 0, 10), "secp256k1") + curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1] From 80e4240ffed80765261112e371f5a90067889650 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 15:30:49 +0200 Subject: [PATCH 3/4] support for repr(VerifyingKey) for hypothesis, falsifying examples are easier to check and reproduce when the key can be printed in form that can be put into code --- src/ecdsa/keys.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ecdsa/keys.py b/src/ecdsa/keys.py index 4f926429..b0898411 100644 --- a/src/ecdsa/keys.py +++ b/src/ecdsa/keys.py @@ -125,6 +125,11 @@ def __init__(self, _error__please_use_generate=None): self.default_hashfunc = None self.pubkey = None + def __repr__(self): + pub_key = self.to_string("compressed") + return "VerifyingKey.from_string({0!r}, {1!r}, {2})".format( + pub_key, self.curve, self.default_hashfunc().name) + @classmethod def from_public_point(cls, point, curve=NIST192p, hashfunc=sha1): """ From 2518ec25d0f88c4a09919485656c3792426f58c3 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 16:01:54 +0200 Subject: [PATCH 4/4] fuzzing of DER signatures with hypothesis use hypothesis to generate malformed signatures by introducing different changes for different curves made with different hashes --- .gitignore | 1 + build-requirements-2.6.txt | 1 + build-requirements-3.3.txt | 2 + build-requirements.txt | 1 + src/ecdsa/test_malformed_sigs.py | 139 +++++++++++++++++++++++-------- tox.ini | 4 + 6 files changed, 111 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 49bbeffb..05fbfd4a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ coverage-html .tox nosetests.xml t/ +.hypothesis/ # Translations *.mo diff --git a/build-requirements-2.6.txt b/build-requirements-2.6.txt index 980e00df..9f39acd0 100644 --- a/build-requirements-2.6.txt +++ b/build-requirements-2.6.txt @@ -2,3 +2,4 @@ tox coveralls<1.3.0 idna<2.8 unittest2 +hypothesis<3 diff --git a/build-requirements-3.3.txt b/build-requirements-3.3.txt index 68f8c292..28dd401b 100644 --- a/build-requirements-3.3.txt +++ b/build-requirements-3.3.txt @@ -3,3 +3,5 @@ pluggy<0.6 tox<3 wheel<0.30 virtualenv==15.2.0 +enum34 +hypothesis<3.44 diff --git a/build-requirements.txt b/build-requirements.txt index 6918d2e8..6aeb6111 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1,2 +1,3 @@ tox python-coveralls +hypothesis diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index fffb1b3b..dffc3842 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -1,51 +1,116 @@ from __future__ import with_statement, division -import pytest import hashlib +try: + from hashlib import algorithms_available +except ImportError: + algorithms_available = [ + "md5", "sha1", "sha224", "sha256", "sha384", "sha512"] +from functools import partial +import pytest +from six import binary_type +import hypothesis.strategies as st +from hypothesis import note, assume, given, settings -from six import b, binary_type -from .keys import SigningKey, VerifyingKey +from .keys import SigningKey from .keys import BadSignatureError from .util import sigencode_der, sigencode_string from .util import sigdecode_der, sigdecode_string -from .curves import curves, NIST256p, NIST521p +from .curves import curves, NIST256p -der_sigs = [] -example_data = b("some data to sign") -# Just NIST256p with SHA256 is 560 test cases, all curves with all hashes is -# few thousand slow test cases; execute the most interesting only +example_data = b"some data to sign" +"""Since the data is hashed for processing, really any string will do.""" -#for curve in curves: -for curve in [NIST521p]: - #for hash_alg in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]: - for hash_alg in ["sha256"]: - key = SigningKey.generate(curve) - signature = key.sign(example_data, hashfunc=getattr(hashlib, hash_alg), - sigencode=sigencode_der) - for pos in range(len(signature)): - for xor in (1<