From 06ad384946f9c36793f834f4241834372291131a Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Wed, 23 Oct 2019 10:14:45 +0200 Subject: [PATCH 01/14] decision coverage: make git checkout work reliably also stop copying diff-instrumental.py, it's now in master so it will be present when we checkout the base commit --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f2cbba52..195150c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ before_install: TRAVIS_COMMIT_RANGE=$PR_FIRST^..$TRAVIS_COMMIT fi # sanity check current commit - - git rev-parse HEAD + - BRANCH=$(git rev-parse HEAD) - echo "TRAVIS_COMMIT_RANGE=$TRAVIS_COMMIT_RANGE" - git fetch origin master:refs/remotes/origin/master @@ -78,7 +78,6 @@ install: script: - if [[ $TOX_ENV ]]; then tox -e $TOX_ENV; fi - tox -e speed - - cp diff-instrumental.py diff-instrumental-2.py - | if [[ $INSTRUMENTAL && $TRAVIS_PULL_REQUEST != "false" ]]; then git checkout $PR_FIRST^ @@ -86,8 +85,8 @@ script: files="$(ls src/ecdsa/test*.py | grep -v test_malformed_sigs.py)" instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` $files instrumental -f .instrumental.cov -s - instrumental -f .instrumental.cov -s | python diff-instrumental-2.py --save .diff-instrumental - git checkout $TRAVIS_COMMIT + instrumental -f .instrumental.cov -s | python diff-instrumental.py --save .diff-instrumental + git checkout $BRANCH instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` $files instrumental -f .instrumental.cov -sr fi @@ -98,11 +97,11 @@ script: instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` $files instrumental -f .instrumental.cov -s # just log the values when merging - instrumental -f .instrumental.cov -s | python diff-instrumental-2.py + instrumental -f .instrumental.cov -s | python diff-instrumental.py fi - | if [[ $INSTRUMENTAL && $TRAVIS_PULL_REQUEST != "false" ]]; then - instrumental -f .instrumental.cov -s | python diff-instrumental-2.py --read .diff-instrumental --fail-under 70 --max-difference -0.1 + instrumental -f .instrumental.cov -s | python diff-instrumental.py --read .diff-instrumental --fail-under 70 --max-difference -0.1 fi after_success: - if [[ -z $INSTRUMENTAL ]]; then coveralls; fi From 881274a0c0d32e844ffc0b8a011c20d6784a3586 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 14:18:37 +0200 Subject: [PATCH 02/14] 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 bce756251b4bd6902dec54519a5d7f589d2e2be5 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 14:19:45 +0200 Subject: [PATCH 03/14] 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 de83837110104a32d20581bd0926865c1e5019a0 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 15:30:49 +0200 Subject: [PATCH 04/14] 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 a23aa656059ea43787e6ec0200159bd2bfaee7f0 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 16:01:54 +0200 Subject: [PATCH 05/14] 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 | 2 + src/ecdsa/test_malformed_sigs.py | 146 +++++++++++++++++++++++-------- tox.ini | 5 ++ 6 files changed, 120 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..072f7a9d 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1,2 +1,4 @@ tox python-coveralls +hypothesis +pytest>=4.6.0 diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index fffb1b3b..2c2b2780 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -1,51 +1,123 @@ 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 +import sys +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<= (2, 7): + # deadline=5s because NIST521p are slow to verify + params["deadline"] = 5000 + + +@settings(**params) +@given(st_fuzzed_sig()) +def test_fuzzed_der_signatures(args): + verifying_key, sig = args + + with pytest.raises(BadSignatureError): + verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) #### diff --git a/tox.ini b/tox.ini index a10f3965..4f31ae61 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,14 @@ envlist = py26, py27, py33, py34, py35, py36, py37, py38, py, pypy, pypy3 deps = py{33}: py<1.5 py{33}: pytest<3.3 + py{33}: enum34 + py{33}: hypothesis<3.44 py{26}: unittest2 + py{26}: hypothesis<3 py{26,27,34,35,36,37,38,py,py3}: pytest + py{27,34,35,36,37,38,py,py3}: hypothesis py: pytest + py: hypothesis py{33}: wheel<0.30 coverage commands = coverage run --branch -m pytest {posargs:src/ecdsa} From 0173834319ef686931c4397fdde0c918491e5fa6 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 17:32:10 +0200 Subject: [PATCH 06/14] run all tests in instrumental since now test_malformed_sigs.py executes quickly, we can run it under instrumental --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 195150c0..8d1f6a89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,14 +87,12 @@ script: instrumental -f .instrumental.cov -s instrumental -f .instrumental.cov -s | python diff-instrumental.py --save .diff-instrumental git checkout $BRANCH - instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` $files + instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` src/ecdsa instrumental -f .instrumental.cov -sr fi - | if [[ $INSTRUMENTAL && $TRAVIS_PULL_REQUEST == "false" ]]; then - # exclude the super slow test_malformed_sigs.py, until #127 is merged - files="$(ls src/ecdsa/test*.py | grep -v test_malformed_sigs.py)" - instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` $files + instrumental -t ecdsa -i 'test.*|.*_version' `which pytest` src/ecdsa instrumental -f .instrumental.cov -s # just log the values when merging instrumental -f .instrumental.cov -s | python diff-instrumental.py From 1f9d7be7328579c74a5a63c65bbcff7c3965eb24 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 20:20:12 +0200 Subject: [PATCH 07/14] test random ECDSA-Sig-Value --- src/ecdsa/test_malformed_sigs.py | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index 2c2b2780..dfc94c80 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -18,6 +18,7 @@ from .util import sigencode_der, sigencode_string from .util import sigdecode_der, sigdecode_string from .curves import curves, NIST256p +from .der import encode_integer, encode_sequence example_data = b"some data to sign" @@ -120,6 +121,46 @@ def test_fuzzed_der_signatures(args): verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) +@st.composite +def st_random_der_ecdsa_sig_value(draw): + """ + Hypothesis strategy for selecting random values and encoding them + to ECDSA-Sig-Value object:: + + ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER + } + """ + name, verifying_key, _ = draw(st.sampled_from(keys_and_sigs)) + note("Configuration: {0}".format(name)) + order = verifying_key.curve.order + + # the encode_integer doesn't suport negative numbers, would be nice + # to generate them too, but we have coverage for remove_integer() + # verifying that it doesn't accept them, so meh + r = draw(st.integers(min_value=0) | + st.integers(min_value=order >> 2, max_value=order+1)) + s = draw(st.integers(min_value=0) | + st.integers(min_value=order >> 2, max_value=order+1)) + + sig = encode_sequence(encode_integer(r), encode_integer(s)) + + return verifying_key, sig + + +@given(st_random_der_ecdsa_sig_value()) +def test_random_der_ecdsa_sig_value(params): + """ + Check if random values encoded in ECDSA-Sig-Value structure are rejected + as signature. + """ + verifying_key, sig = params + + with pytest.raises(BadSignatureError): + verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) + + #### # # For string encoded signatures, only the length of string is important From 46b335ef717e91e87f8b397ddd0352bb4eb93e87 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 21:03:24 +0200 Subject: [PATCH 08/14] generalise st_fuzzed_sig() --- src/ecdsa/test_malformed_sigs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index dfc94c80..cb3812cd 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -61,7 +61,7 @@ def test_signatures(verifying_key, signature): @st.composite -def st_fuzzed_sig(draw): +def st_fuzzed_sig(draw, keys_and_sigs): """ Hypothesis strategy that generates pairs of VerifyingKey and malformed signatures created by fuzzing of a valid signature. @@ -113,7 +113,7 @@ def st_fuzzed_sig(draw): @settings(**params) -@given(st_fuzzed_sig()) +@given(st_fuzzed_sig(keys_and_sigs)) def test_fuzzed_der_signatures(args): verifying_key, sig = args From 21f199c6c447eff105fa0640821a7fffa15d6821 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 21:04:18 +0200 Subject: [PATCH 09/14] test malformed string singatues with hypothesis --- src/ecdsa/test_malformed_sigs.py | 55 +++++++++++--------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index cb3812cd..301307c7 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -161,40 +161,21 @@ def test_random_der_ecdsa_sig_value(params): verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) -#### -# -# For string encoded signatures, only the length of string is important -# -#### - -str_sigs = [] - -#for curve in curves: -for curve in [NIST256p]: - #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_string) - for trunc in range(len(signature)): - str_sigs.append(pytest.param( - key.verifying_key, hash_alg, - signature, trunc, - id="{0}-{1}-trunc-{2}".format( - curve.name, hash_alg, trunc))) - - -@pytest.mark.parametrize("verifying_key,hash_alg,signature,trunc", str_sigs) -def test_truncated_string_signatures(verifying_key, hash_alg, signature, trunc): - # check if a malformed string encoded signature causes the same exception - # to be raised irrespective of the type of error - sig = bytearray(signature) - sig = sig[:trunc] - sig = binary_type(sig) - - try: - verifying_key.verify(sig, example_data, getattr(hashlib, hash_alg), - sigdecode_string) - assert False - except BadSignatureError: - assert True +keys_and_string_sigs = [ + (name, verifying_key, + sigencode_string(*sigdecode_der(sig, verifying_key.curve.order), + order=verifying_key.curve.order)) + for name, verifying_key, sig in keys_and_sigs] +""" +Name of the curve+hash combination, VerifyingKey and signature as a +byte string. +""" + + +@settings(**params) +@given(st_fuzzed_sig(keys_and_string_sigs)) +def test_fuzzed_string_signatures(params): + verifying_key, sig = params + + with pytest.raises(BadSignatureError): + verifying_key.verify(sig, example_data, sigdecode=sigdecode_string) From d205606c949d940bb8438b4520ddd5f4a118c3d1 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 21:42:28 +0200 Subject: [PATCH 10/14] test signature decoding with random DER objects --- src/ecdsa/test_malformed_sigs.py | 88 +++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index 301307c7..240f7253 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -18,7 +18,8 @@ from .util import sigencode_der, sigencode_string from .util import sigdecode_der, sigdecode_string from .curves import curves, NIST256p -from .der import encode_integer, encode_sequence +from .der import encode_integer, encode_bitstring, encode_octet_string, \ + encode_oid, encode_sequence, encode_constructed example_data = b"some data to sign" @@ -161,6 +162,91 @@ def test_random_der_ecdsa_sig_value(params): verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) +def st_der_integer(*args, **kwargs): + """ + Hypothesis strategy that returns a random positive integer as DER + INTEGER. + Parameters are passed to hypothesis.strategy.integer. + """ + if "min_value" not in kwargs: + kwargs["min_value"] = 0 + return st.builds(encode_integer, st.integers(*args, **kwargs)) + + +@st.composite +def st_der_bit_string(draw, *args, **kwargs): + """ + Hypothesis strategy that returns a random DER BIT STRING. + Parameters are passed to hypothesis.strategy.binary. + """ + data = draw(st.binary(*args, **kwargs)) + if data: + unused = draw(st.integers(min_value=0, max_value=7)) + data = bytearray(data) + data[-1] &= - (2**unused) + data = bytes(data) + else: + unused = 0 + return encode_bitstring(data, unused) + + +def st_der_octet_string(*args, **kwargs): + """ + Hypothesis strategy that returns a random DER OCTET STRING object. + Parameters are passed to hypothesis.strategy.binary + """ + return st.builds(encode_octet_string, st.binary(*args, **kwargs)) + + +def st_der_null(): + """ + Hypothesis strategy that returns DER NULL object. + """ + return st.just(b'\x05\x00') + + +@st.composite +def st_der_oid(draw): + """ + Hypothesis strategy that returns DER OBJECT IDENTIFIER objects. + """ + first = draw(st.integers(min_value=0, max_value=2)) + second = draw(st.integers(min_value=0, max_value=39)) + rest = draw(st.lists(st.integers(min_value=0))) + return encode_oid(first, second, *rest) + + +def st_der(): + """ + Hypothesis strategy that returns random DER structures. + + A valid DER structure is any primitive object, an octet encoding + of a valid DER structure, sequence of valid DER objects or a constructed + encoding of any of the above. + """ + return st.recursive( + st.just(b'') | st_der_integer() | st_der_bit_string() | + st_der_octet_string() | st_der_null() | st_der_oid(), + lambda children: + st.builds(lambda x: encode_octet_string(x), st.one_of(children)) | + st.builds(lambda x: encode_bitstring(x, 0), st.one_of(children)) | + st.builds(lambda x: encode_sequence(*x), st.lists(children)) | + st.builds(lambda tag, x: + encode_constructed(tag, x), + st.integers(min_value=0, max_value=0x3f), + st.one_of(children)) + ) + + +@given(st.sampled_from(keys_and_sigs), st_der()) +def test_random_der_as_signature(params, der): + """Check if random DER structures are rejected as signature""" + name, verifying_key, _ = params + + with pytest.raises(BadSignatureError): + verifying_key.verify(der, example_data, sigdecode=sigdecode_der) + + keys_and_string_sigs = [ (name, verifying_key, sigencode_string(*sigdecode_der(sig, verifying_key.curve.order), From abc7744830436aaa8c11845dc992f9c9d596b851 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 21:44:15 +0200 Subject: [PATCH 11/14] test verify with random byte strings --- src/ecdsa/test_malformed_sigs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index 240f7253..f1070226 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -247,6 +247,15 @@ def test_random_der_as_signature(params, der): verifying_key.verify(der, example_data, sigdecode=sigdecode_der) +@given(st.sampled_from(keys_and_sigs), st.binary()) +def test_random_bytes_as_signature(params, der): + """Check if random bytes are rejected as signature""" + name, verifying_key, _ = params + + with pytest.raises(BadSignatureError): + verifying_key.verify(der, example_data, sigdecode=sigdecode_der) + + keys_and_string_sigs = [ (name, verifying_key, sigencode_string(*sigdecode_der(sig, verifying_key.curve.order), From 5c1ec6a371f0a69c3517c5a9fa9bf801d7315b83 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 21:50:38 +0200 Subject: [PATCH 12/14] set the settings.deadline for all signature tests --- src/ecdsa/test_malformed_sigs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index f1070226..068363d8 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -150,6 +150,7 @@ def st_random_der_ecdsa_sig_value(draw): return verifying_key, sig +@settings(**params) @given(st_random_der_ecdsa_sig_value()) def test_random_der_ecdsa_sig_value(params): """ @@ -238,6 +239,7 @@ def st_der(): ) +@settings(**params) @given(st.sampled_from(keys_and_sigs), st_der()) def test_random_der_as_signature(params, der): """Check if random DER structures are rejected as signature""" @@ -247,6 +249,7 @@ def test_random_der_as_signature(params, der): verifying_key.verify(der, example_data, sigdecode=sigdecode_der) +@settings(**params) @given(st.sampled_from(keys_and_sigs), st.binary()) def test_random_bytes_as_signature(params, der): """Check if random bytes are rejected as signature""" From 44e58ac896f7bb131113638176e4af7ffa6a9364 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 26 Oct 2019 22:07:18 +0200 Subject: [PATCH 13/14] report hypothesis stats in run since hypothesis executes good few hundred test cases, do report that they have been run when the user runs the test suite specified in readme... --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 4f31ae61..fbaf823e 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,7 @@ commands = coverage run --branch -m pytest {posargs:src/ecdsa} [testenv:coverage] sitepackages=True -commands = coverage run --branch -m pytest {posargs:src/ecdsa} +commands = coverage run --branch -m pytest --hypothesis-show-statistics {posargs:src/ecdsa} [testenv:speed] commands = {envpython} speed.py From b6a6147453e7e8fde387a46f56fe5daaecded490 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sun, 27 Oct 2019 01:51:47 +0200 Subject: [PATCH 14/14] ensure consistent coverage for sigdecode_der make sure we hit the currently defined two checks in the sigdecode_der() function --- src/ecdsa/test_malformed_sigs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py index 068363d8..645b9879 100644 --- a/src/ecdsa/test_malformed_sigs.py +++ b/src/ecdsa/test_malformed_sigs.py @@ -11,7 +11,7 @@ import sys from six import binary_type import hypothesis.strategies as st -from hypothesis import note, assume, given, settings +from hypothesis import note, assume, given, settings, example from .keys import SigningKey from .keys import BadSignatureError @@ -251,6 +251,15 @@ def test_random_der_as_signature(params, der): @settings(**params) @given(st.sampled_from(keys_and_sigs), st.binary()) +@example( + keys_and_sigs[0], + encode_sequence(encode_integer(0), encode_integer(0))) +@example( + keys_and_sigs[0], + encode_sequence(encode_integer(1), encode_integer(1)) + b'\x00') +@example( + keys_and_sigs[0], + encode_sequence(*[encode_integer(1)] * 3)) def test_random_bytes_as_signature(params, der): """Check if random bytes are rejected as signature""" name, verifying_key, _ = params