Hello community,

here is the log from the commit of package python-ecdsa for openSUSE:Factory 
checked in at 2019-11-04 17:08:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ecdsa (Old)
 and      /work/SRC/openSUSE:Factory/.python-ecdsa.new.2990 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ecdsa"

Mon Nov  4 17:08:40 2019 rev:10 rq:742539 version:0.13.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ecdsa/python-ecdsa.changes        
2019-05-17 23:36:31.954129309 +0200
+++ /work/SRC/openSUSE:Factory/.python-ecdsa.new.2990/python-ecdsa.changes      
2019-11-04 17:08:44.120410412 +0100
@@ -1,0 +2,8 @@
+Mon Oct 14 21:41:55 UTC 2019 - Robert Schweikert <rjsch...@suse.com>
+
+- updated to 0.13.3 (bsc#1153165)
+  + CVE-2019-14853 DOS atack during signature decoding
+  + CVE-2019-14859 signature malleability caused by insufficient checks
+    of DER encoding
+
+-------------------------------------------------------------------
@@ -14,0 +23,5 @@
+Fri Sep 21 12:51:24 UTC 2018 - John Paul Adrian Glaubitz 
<adrian.glaub...@suse.com>
+
+- Include in SLE-12 (fate#323875, bsc#1054413)
+
+-------------------------------------------------------------------
@@ -23 +36 @@
-- update to 0.13
+- update to 0.13 (bsc#962291)

Old:
----
  ecdsa-0.13.2.tar.gz

New:
----
  ecdsa-0.13.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-ecdsa.spec ++++++
--- /var/tmp/diff_new_pack.0maHx4/_old  2019-11-04 17:08:44.880411224 +0100
+++ /var/tmp/diff_new_pack.0maHx4/_new  2019-11-04 17:08:44.892411237 +0100
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-ecdsa
-Version:        0.13.2
+Version:        0.13.3
 Release:        0
 Summary:        ECDSA cryptographic signature library (pure python)
 License:        MIT

++++++ ecdsa-0.13.2.tar.gz -> ecdsa-0.13.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/NEWS new/ecdsa-0.13.3/NEWS
--- old/ecdsa-0.13.2/NEWS       2019-04-17 21:29:43.000000000 +0200
+++ new/ecdsa-0.13.3/NEWS       2019-10-07 15:56:15.000000000 +0200
@@ -1,3 +1,10 @@
+* Release 0.13.3 (07 Oct 2019)
+
+Fix CVE-2019-14853 - possible DoS caused by malformed signature decoding and
+signature malleability.
+
+Also harden key decoding from string and DER encodings.
+
 * Release 0.13.2 (17 Apr 2019)
 
 Restore compatibility of setup.py with Python 2.6 and 2.7.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/PKG-INFO new/ecdsa-0.13.3/PKG-INFO
--- old/ecdsa-0.13.2/PKG-INFO   2019-04-17 21:33:44.000000000 +0200
+++ new/ecdsa-0.13.3/PKG-INFO   2019-10-07 16:01:32.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ecdsa
-Version: 0.13.2
+Version: 0.13.3
 Summary: ECDSA cryptographic signature library (pure python)
 Home-page: http://github.com/warner/python-ecdsa
 Author: Brian Warner
@@ -81,6 +81,7 @@
         more for the wrapper. To run them all, do this:
         
             python setup.py test
+            tox -e coverage
         
         On my 2014 Mac Mini, the combined tests take about 20 seconds to run. 
On a
         2.4GHz P4 Linux box, they take 81 seconds.
@@ -126,7 +127,8 @@
         `SigningKey.from_string(s, curve)` . This short form does not record 
the
         curve, so you must be sure to tell from_string() the same curve you 
used for
         the original key. The short form of a NIST192p-based signing key is 
just 24
-        bytes long.
+        bytes long. If the point encoding is invalid or it does not lie on the
+        specified curve, `from_string()` will raise MalformedPointError.
         
             from ecdsa import SigningKey, NIST384p
             sk = SigningKey.generate(curve=NIST384p)
@@ -140,7 +142,8 @@
         is a shorter binary form of the same data.
         `SigningKey.from_pem()/.from_der()` will undo this serialization. These
         formats include the curve name, so you do not need to pass in a curve
-        identifier to the deserializer.
+        identifier to the deserializer. In case the file is malformed 
`from_der()`
+        and `from_pem()` will raise UnexpectedDER or MalformedPointError.
         
             from ecdsa import SigningKey, NIST384p
             sk = SigningKey.generate(curve=NIST384p)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/README.md new/ecdsa-0.13.3/README.md
--- old/ecdsa-0.13.2/README.md  2019-04-17 21:23:20.000000000 +0200
+++ new/ecdsa-0.13.3/README.md  2019-10-07 15:51:57.000000000 +0200
@@ -73,6 +73,7 @@
 more for the wrapper. To run them all, do this:
 
     python setup.py test
+    tox -e coverage
 
 On my 2014 Mac Mini, the combined tests take about 20 seconds to run. On a
 2.4GHz P4 Linux box, they take 81 seconds.
@@ -118,7 +119,8 @@
 `SigningKey.from_string(s, curve)` . This short form does not record the
 curve, so you must be sure to tell from_string() the same curve you used for
 the original key. The short form of a NIST192p-based signing key is just 24
-bytes long.
+bytes long. If the point encoding is invalid or it does not lie on the
+specified curve, `from_string()` will raise MalformedPointError.
 
     from ecdsa import SigningKey, NIST384p
     sk = SigningKey.generate(curve=NIST384p)
@@ -132,7 +134,8 @@
 is a shorter binary form of the same data.
 `SigningKey.from_pem()/.from_der()` will undo this serialization. These
 formats include the curve name, so you do not need to pass in a curve
-identifier to the deserializer.
+identifier to the deserializer. In case the file is malformed `from_der()`
+and `from_pem()` will raise UnexpectedDER or MalformedPointError.
 
     from ecdsa import SigningKey, NIST384p
     sk = SigningKey.generate(curve=NIST384p)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/__init__.py 
new/ecdsa-0.13.3/ecdsa/__init__.py
--- old/ecdsa-0.13.2/ecdsa/__init__.py  2019-04-17 21:23:20.000000000 +0200
+++ new/ecdsa-0.13.3/ecdsa/__init__.py  2019-10-07 15:51:57.000000000 +0200
@@ -1,9 +1,12 @@
 __all__ = ["curves", "der", "ecdsa", "ellipticcurve", "keys", "numbertheory",
            "test_pyecdsa", "util", "six"]
-from .keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError
+from .keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError,\
+        MalformedPointError
 from .curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1
+from .der import UnexpectedDER
 
 _hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError,
+                  MalformedPointError, UnexpectedDER,
                   NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1]
 del _hush_pyflakes
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/_version.py 
new/ecdsa-0.13.3/ecdsa/_version.py
--- old/ecdsa-0.13.2/ecdsa/_version.py  2019-04-17 21:33:44.000000000 +0200
+++ new/ecdsa-0.13.3/ecdsa/_version.py  2019-10-07 16:01:32.000000000 +0200
@@ -4,8 +4,8 @@
 # unpacked source archive. Distribution tarballs contain a pre-generated copy
 # of this file.
 
-version_version = '0.13.2'
-version_full = 'bb359d32e93acc3eb4d216aff4ba0e7531599cfb'
+version_version = '0.13.3'
+version_full = '7add2213c992f51267eed8288b560f3f4108a28d'
 def get_versions(default={}, verbose=False):
     return {'version': version_version, 'full': version_full}
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/der.py 
new/ecdsa-0.13.3/ecdsa/der.py
--- old/ecdsa-0.13.2/ecdsa/der.py       2019-04-17 21:23:20.000000000 +0200
+++ new/ecdsa-0.13.3/ecdsa/der.py       2019-10-07 15:51:57.000000000 +0200
@@ -60,10 +60,15 @@
     return tag, body, rest
 
 def remove_sequence(string):
+    if not string:
+        raise UnexpectedDER("Empty string does not encode a sequence")
     if not string.startswith(b("\x30")):
-        n = string[0] if isinstance(string[0], integer_types) else 
ord(string[0])
-        raise UnexpectedDER("wanted sequence (0x30), got 0x%02x" % n)
+        n = string[0] if isinstance(string[0], integer_types) else \
+                ord(string[0])
+        raise UnexpectedDER("wanted type 'sequence' (0x30), got 0x%02x" % n)
     length, lengthlength = read_length(string[1:])
+    if length > len(string) - 1 - lengthlength:
+        raise UnexpectedDER("Length longer than the provided buffer")
     endseq = 1+lengthlength+length
     return string[1+lengthlength:endseq], string[endseq:]
 
@@ -96,14 +101,33 @@
     return tuple(numbers), rest
 
 def remove_integer(string):
+    if not string:
+        raise UnexpectedDER("Empty string is an invalid encoding of an "
+                            "integer")
     if not string.startswith(b("\x02")):
-        n = string[0] if isinstance(string[0], integer_types) else 
ord(string[0])
-        raise UnexpectedDER("wanted integer (0x02), got 0x%02x" % n)
+        n = string[0] if isinstance(string[0], integer_types) \
+                else ord(string[0])
+        raise UnexpectedDER("wanted type 'integer' (0x02), got 0x%02x" % n)
     length, llen = read_length(string[1:])
+    if length > len(string) - 1 - llen:
+        raise UnexpectedDER("Length longer than provided buffer")
+    if length == 0:
+        raise UnexpectedDER("0-byte long encoding of integer")
     numberbytes = string[1+llen:1+llen+length]
     rest = string[1+llen+length:]
-    nbytes = numberbytes[0] if isinstance(numberbytes[0], integer_types) else 
ord(numberbytes[0])
-    assert nbytes < 0x80 # can't support negative numbers yet
+    msb = numberbytes[0] if isinstance(numberbytes[0], integer_types) \
+            else ord(numberbytes[0])
+    if not msb < 0x80:
+        raise UnexpectedDER("Negative integers are not supported")
+    # check if the encoding is the minimal one (DER requirement)
+    if length > 1 and not msb:
+        # leading zero byte is allowed if the integer would have been
+        # considered a negative number otherwise
+        smsb = numberbytes[1] if isinstance(numberbytes[1], integer_types) \
+                else ord(numberbytes[1])
+        if smsb < 0x80:
+            raise UnexpectedDER("Invalid encoding of integer, unnecessary "
+                                "zero padding bytes")
     return int(binascii.hexlify(numberbytes), 16), rest
 
 def read_number(string):
@@ -133,6 +157,8 @@
     return int2byte(0x80|llen) + s
 
 def read_length(string):
+    if not string:
+        raise UnexpectedDER("Empty string can't encode valid length value")
     num = string[0] if isinstance(string[0], integer_types) else ord(string[0])
     if not (num & 0x80):
         # short form
@@ -140,8 +166,14 @@
     # else long-form: b0&0x7f is number of additional base256 length bytes,
     # big-endian
     llen = num & 0x7f
+    if not llen:
+        raise UnexpectedDER("Invalid length encoding, length of length is 0")
     if llen > len(string)-1:
-        raise UnexpectedDER("ran out of length bytes")
+        raise UnexpectedDER("Length of length longer than provided buffer")
+    # verify that the encoding is minimal possible (DER requirement)
+    msb = string[1] if isinstance(string[1], integer_types) else ord(string[1])
+    if not msb or llen == 1 and msb < 0x80:
+        raise UnexpectedDER("Not minimal encoding of length")
     return int(binascii.hexlify(string[1:1+llen]), 16), 1+llen
 
 def remove_bitstring(string):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/keys.py 
new/ecdsa-0.13.3/ecdsa/keys.py
--- old/ecdsa-0.13.2/ecdsa/keys.py      2019-04-17 21:23:20.000000000 +0200
+++ new/ecdsa-0.13.3/ecdsa/keys.py      2019-10-07 15:51:57.000000000 +0200
@@ -3,10 +3,11 @@
 from . import ecdsa
 from . import der
 from . import rfc6979
+from . import ellipticcurve
 from .curves import NIST192p, find_curve
 from .util import string_to_number, number_to_string, randrange
 from .util import sigencode_string, sigdecode_string
-from .util import oid_ecPublicKey, encoded_oid_ecPublicKey
+from .util import oid_ecPublicKey, encoded_oid_ecPublicKey, MalformedSignature
 from .six import PY3, b
 from hashlib import sha1
 
@@ -15,6 +16,11 @@
 class BadDigestError(Exception):
     pass
 
+
+class MalformedPointError(AssertionError):
+    pass
+
+
 class VerifyingKey:
     def __init__(self, _error__please_use_generate=None):
         if not _error__please_use_generate:
@@ -33,17 +39,21 @@
     def from_string(klass, string, curve=NIST192p, hashfunc=sha1,
                     validate_point=True):
         order = curve.order
-        assert len(string) == curve.verifying_key_length, \
-               (len(string), curve.verifying_key_length)
+        if len(string) != curve.verifying_key_length:
+            raise MalformedPointError(
+                "Malformed encoding of public point. Expected string {0} bytes"
+                " long, received {1} bytes long string".format(
+                    curve.verifying_key_length, len(string)))
         xs = string[:curve.baselen]
         ys = string[curve.baselen:]
-        assert len(xs) == curve.baselen, (len(xs), curve.baselen)
-        assert len(ys) == curve.baselen, (len(ys), curve.baselen)
+        if len(xs) != curve.baselen:
+            raise MalformedPointError("Unexpected length of encoded x")
+        if len(ys) != curve.baselen:
+            raise MalformedPointError("Unexpected length of encoded y")
         x = string_to_number(xs)
         y = string_to_number(ys)
-        if validate_point:
-            assert ecdsa.point_is_valid(curve.generator, x, y)
-        from . import ellipticcurve
+        if validate_point and not ecdsa.point_is_valid(curve.generator, x, y):
+            raise MalformedPointError("Point does not lie on the curve")
         point = ellipticcurve.Point(curve.curve, x, y, order)
         return klass.from_public_point(point, curve, hashfunc)
 
@@ -65,13 +75,18 @@
         if empty != b(""):
             raise der.UnexpectedDER("trailing junk after DER pubkey objects: 
%s" %
                                     binascii.hexlify(empty))
-        assert oid_pk == oid_ecPublicKey, (oid_pk, oid_ecPublicKey)
+        if oid_pk != oid_ecPublicKey:
+            raise der.UnexpectedDER(
+                "Unexpected OID in encoding, received {0}, expected {1}"
+                .format(oid_pk, oid_ecPublicKey))
         curve = find_curve(oid_curve)
         point_str, empty = der.remove_bitstring(point_str_bitstring)
         if empty != b(""):
             raise der.UnexpectedDER("trailing junk after pubkey pointstring: 
%s" %
                                     binascii.hexlify(empty))
-        assert point_str.startswith(b("\x00\x04"))
+        if not point_str.startswith(b("\x00\x04")):
+            raise der.UnexpectedDER(
+                    "Unsupported or invalid encoding of pubcli key")
         return klass.from_string(point_str[2:], curve)
 
     def to_string(self):
@@ -106,11 +121,14 @@
                                  "for your digest (%d)" % (self.curve.name,
                                                            8*len(digest)))
         number = string_to_number(digest)
-        r, s = sigdecode(signature, self.pubkey.order)
+        try:
+            r, s = sigdecode(signature, self.pubkey.order)
+        except (der.UnexpectedDER, MalformedSignature) as e:
+            raise BadSignatureError("Malformed formatting of signature", e)
         sig = ecdsa.Signature(r, s)
         if self.pubkey.verifies(number, sig):
             return True
-        raise BadSignatureError
+        raise BadSignatureError("Signature verification failed")
 
 class SigningKey:
     def __init__(self, _error__please_use_generate=None):
@@ -134,7 +152,10 @@
         self.default_hashfunc = hashfunc
         self.baselen = curve.baselen
         n = curve.order
-        assert 1 <= secexp < n
+        if not 1 <= secexp < n:
+            raise MalformedPointError(
+                "Invalid value for secexp, expected integer between 1 and {0}"
+                .format(n))
         pubkey_point = curve.generator*secexp
         pubkey = ecdsa.Public_key(curve.generator, pubkey_point)
         pubkey.order = n
@@ -146,7 +167,10 @@
 
     @classmethod
     def from_string(klass, string, curve=NIST192p, hashfunc=sha1):
-        assert len(string) == curve.baselen, (len(string), curve.baselen)
+        if len(string) != curve.baselen:
+            raise MalformedPointError(
+                "Invalid length of private key, received {0}, expected {1}"
+                .format(len(string), curve.baselen))
         secexp = string_to_number(string)
         return klass.from_secret_exponent(secexp, curve, hashfunc)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/test_der.py 
new/ecdsa-0.13.3/ecdsa/test_der.py
--- old/ecdsa-0.13.2/ecdsa/test_der.py  1970-01-01 01:00:00.000000000 +0100
+++ new/ecdsa-0.13.3/ecdsa/test_der.py  2019-10-07 15:51:57.000000000 +0200
@@ -0,0 +1,88 @@
+
+# compatibility with Python 2.6, for that we need unittest2 package,
+# which is not available on 3.3 or 3.4
+try:
+    import unittest2 as unittest
+except ImportError:
+    import unittest
+from .der import remove_integer, UnexpectedDER, read_length
+from .six import b
+
+class TestRemoveInteger(unittest.TestCase):
+    # DER requires the integers to be 0-padded only if they would be
+    # interpreted as negative, check if those errors are detected
+    def test_non_minimal_encoding(self):
+        with self.assertRaises(UnexpectedDER):
+            remove_integer(b('\x02\x02\x00\x01'))
+
+    def test_negative_with_high_bit_set(self):
+        with self.assertRaises(UnexpectedDER):
+            remove_integer(b('\x02\x01\x80'))
+
+    def test_two_zero_bytes_with_high_bit_set(self):
+        with self.assertRaises(UnexpectedDER):
+            remove_integer(b('\x02\x03\x00\x00\xff'))
+
+    def test_zero_length_integer(self):
+        with self.assertRaises(UnexpectedDER):
+            remove_integer(b('\x02\x00'))
+
+    def test_empty_string(self):
+        with self.assertRaises(UnexpectedDER):
+            remove_integer(b(''))
+
+    def test_encoding_of_zero(self):
+        val, rem = remove_integer(b('\x02\x01\x00'))
+
+        self.assertEqual(val, 0)
+        self.assertFalse(rem)
+
+    def test_encoding_of_127(self):
+        val, rem = remove_integer(b('\x02\x01\x7f'))
+
+        self.assertEqual(val, 127)
+        self.assertFalse(rem)
+
+    def test_encoding_of_128(self):
+        val, rem = remove_integer(b('\x02\x02\x00\x80'))
+
+        self.assertEqual(val, 128)
+        self.assertFalse(rem)
+
+
+class TestReadLength(unittest.TestCase):
+    # DER requires the lengths between 0 and 127 to be encoded using the short
+    # form and lengths above that encoded with minimal number of bytes
+    # necessary
+    def test_zero_length(self):
+        self.assertEqual((0, 1), read_length(b('\x00')))
+
+    def test_two_byte_zero_length(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b('\x81\x00'))
+
+    def test_two_byte_small_length(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b('\x81\x7f'))
+
+    def test_long_form_with_zero_length(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b('\x80'))
+
+    def test_smallest_two_byte_length(self):
+        self.assertEqual((128, 2), read_length(b('\x81\x80')))
+
+    def test_zero_padded_length(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b('\x82\x00\x80'))
+
+    def test_two_three_byte_length(self):
+        self.assertEqual((256, 3), read_length(b'\x82\x01\x00'))
+
+    def test_empty_string(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b(''))
+
+    def test_length_overflow(self):
+        with self.assertRaises(UnexpectedDER):
+            read_length(b('\x83\x01\x00'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/test_malformed_sigs.py 
new/ecdsa-0.13.3/ecdsa/test_malformed_sigs.py
--- old/ecdsa-0.13.2/ecdsa/test_malformed_sigs.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/ecdsa-0.13.3/ecdsa/test_malformed_sigs.py       2019-10-07 
15:51:57.000000000 +0200
@@ -0,0 +1,87 @@
+from __future__ import with_statement, division
+
+import pytest
+import hashlib
+
+from .six import b, binary_type
+from .keys import SigningKey, VerifyingKey
+from .keys import BadSignatureError
+from .util import sigencode_der, sigencode_string
+from .util import sigdecode_der, sigdecode_string
+from .curves import curves, NIST256p, NIST521p
+
+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
+
+#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<<i for i in range(8)):
+                der_sigs.append(pytest.param(
+                    key.verifying_key, hash_alg,
+                    signature, pos, xor,
+                    id="{0}-{1}-pos-{2}-xor-{3}".format(
+                        curve.name, hash_alg, pos, xor)))
+
+
+@pytest.mark.parametrize("verifying_key,hash_alg,signature,pos,xor", der_sigs)
+def test_fuzzed_der_signatures(verifying_key, hash_alg, signature, pos, xor):
+    # check if a malformed DER encoded signature causes the same exception
+    # to be raised irrespective of the type of error
+    sig = bytearray(signature)
+    sig[pos] ^= xor
+    sig = binary_type(sig)
+
+    try:
+        verifying_key.verify(sig, example_data, getattr(hashlib, hash_alg),
+                             sigdecode_der)
+        assert False
+    except BadSignatureError:
+        assert True
+
+
+####
+#
+# 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/test_pyecdsa.py 
new/ecdsa-0.13.3/ecdsa/test_pyecdsa.py
--- old/ecdsa-0.13.2/ecdsa/test_pyecdsa.py      2019-04-17 21:23:20.000000000 
+0200
+++ new/ecdsa-0.13.3/ecdsa/test_pyecdsa.py      2019-10-07 15:51:57.000000000 
+0200
@@ -1,6 +1,9 @@
 from __future__ import with_statement, division
 
-import unittest
+try:
+    import unittest2 as unittest
+except ImportError:
+    import unittest
 import os
 import time
 import shutil
@@ -10,15 +13,17 @@
 
 from .six import b, print_, binary_type
 from .keys import SigningKey, VerifyingKey
-from .keys import BadSignatureError
+from .keys import BadSignatureError, MalformedPointError, BadDigestError
 from . import util
 from .util import sigencode_der, sigencode_strings
 from .util import sigdecode_der, sigdecode_strings
+from .util import encoded_oid_ecPublicKey, MalformedSignature
 from .curves import Curve, UnknownCurveError
 from .curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1
 from .ellipticcurve import Point
 from . import der
 from . import rfc6979
+from . import ecdsa
 
 class SubprocessError(Exception):
     pass
@@ -258,6 +263,47 @@
         pub2 = VerifyingKey.from_pem(pem)
         self.assertTruePubkeysEqual(pub1, pub2)
 
+    def test_vk_from_der_garbage_after_curve_oid(self):
+        type_oid_der = encoded_oid_ecPublicKey
+        curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) + \
+            b('garbage')
+        enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der)
+        point_der = der.encode_bitstring(b'\x00\xff')
+        to_decode = der.encode_sequence(enc_type_der, point_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            VerifyingKey.from_der(to_decode)
+
+    def test_vk_from_der_invalid_key_type(self):
+        type_oid_der = der.encode_oid(*(1, 2, 3))
+        curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1))
+        enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der)
+        point_der = der.encode_bitstring(b'\x00\xff')
+        to_decode = der.encode_sequence(enc_type_der, point_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            VerifyingKey.from_der(to_decode)
+
+    def test_vk_from_der_garbage_after_point_string(self):
+        type_oid_der = encoded_oid_ecPublicKey
+        curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1))
+        enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der)
+        point_der = der.encode_bitstring(b'\x00\xff') + b('garbage')
+        to_decode = der.encode_sequence(enc_type_der, point_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            VerifyingKey.from_der(to_decode)
+
+    def test_vk_from_der_invalid_bitstring(self):
+        type_oid_der = encoded_oid_ecPublicKey
+        curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1))
+        enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der)
+        point_der = der.encode_bitstring(b'\x08\xff')
+        to_decode = der.encode_sequence(enc_type_der, point_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            VerifyingKey.from_der(to_decode)
+
     def test_signature_strings(self):
         priv1 = SigningKey.generate()
         pub1 = priv1.get_verifying_key()
@@ -281,6 +327,86 @@
         self.assertEqual(type(sig_der), binary_type)
         self.assertTrue(pub1.verify(sig_der, data, sigdecode=sigdecode_der))
 
+    def test_sig_decode_strings_with_invalid_count(self):
+        with self.assertRaises(MalformedSignature):
+            sigdecode_strings([b('one'), b('two'), b('three')], 0xff)
+
+    def test_sig_decode_strings_with_wrong_r_len(self):
+        with self.assertRaises(MalformedSignature):
+            sigdecode_strings([b('one'), b('two')], 0xff)
+
+    def test_sig_decode_strings_with_wrong_s_len(self):
+        with self.assertRaises(MalformedSignature):
+            sigdecode_strings([b('\xa0'), b('\xb0\xff')], 0xff)
+
+    def test_verify_with_too_long_input(self):
+        sk = SigningKey.generate()
+        vk = sk.verifying_key
+
+        with self.assertRaises(BadDigestError):
+            vk.verify_digest(None, b('\x00') * 128)
+
+    def test_sk_from_secret_exponent_with_wrong_sec_exponent(self):
+        with self.assertRaises(MalformedPointError):
+            SigningKey.from_secret_exponent(0)
+
+    def test_sk_from_string_with_wrong_len_string(self):
+        with self.assertRaises(MalformedPointError):
+            SigningKey.from_string(b('\x01'))
+
+    def test_sk_from_der_with_junk_after_sequence(self):
+        ver_der = der.encode_integer(1)
+        to_decode = der.encode_sequence(ver_der) + b('garbage')
+
+        with self.assertRaises(der.UnexpectedDER):
+            SigningKey.from_der(to_decode)
+
+    def test_sk_from_der_with_wrong_version(self):
+        ver_der = der.encode_integer(0)
+        to_decode = der.encode_sequence(ver_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            SigningKey.from_der(to_decode)
+
+    def test_sk_from_der_invalid_const_tag(self):
+        ver_der = der.encode_integer(1)
+        privkey_der = der.encode_octet_string(b('\x00\xff'))
+        curve_oid_der = der.encode_oid(*(1, 2, 3))
+        const_der = der.encode_constructed(1, curve_oid_der)
+        to_decode = der.encode_sequence(ver_der, privkey_der, const_der,
+                curve_oid_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            SigningKey.from_der(to_decode)
+
+    def test_sk_from_der_garbage_after_privkey_oid(self):
+        ver_der = der.encode_integer(1)
+        privkey_der = der.encode_octet_string(b('\x00\xff'))
+        curve_oid_der = der.encode_oid(*(1, 2, 3)) + b('garbage')
+        const_der = der.encode_constructed(0, curve_oid_der)
+        to_decode = der.encode_sequence(ver_der, privkey_der, const_der,
+                curve_oid_der)
+
+        with self.assertRaises(der.UnexpectedDER):
+            SigningKey.from_der(to_decode)
+
+    def test_sk_from_der_with_short_privkey(self):
+        ver_der = der.encode_integer(1)
+        privkey_der = der.encode_octet_string(b('\x00\xff'))
+        curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1))
+        const_der = der.encode_constructed(0, curve_oid_der)
+        to_decode = der.encode_sequence(ver_der, privkey_der, const_der,
+                curve_oid_der)
+
+        sk = SigningKey.from_der(to_decode)
+        self.assertEqual(sk.privkey.secret_multiplier, 255)
+
+    def test_sign_with_too_long_hash(self):
+        sk = SigningKey.from_secret_exponent(12)
+
+        with self.assertRaises(BadDigestError):
+            sk.sign_digest(b('\xff') * 64)
+
     def test_hashfunc(self):
         sk = SigningKey.generate(curve=NIST256p, hashfunc=sha256)
         data = b("security level is 128 bits")
@@ -299,6 +425,49 @@
                                        curve=NIST256p)
         self.assertTrue(vk3.verify(sig, data, hashfunc=sha256))
 
+    def test_decoding_with_malformed_uncompressed(self):
+        enc = b('\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3'
+                '\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4'
+                'z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*')
+
+        with self.assertRaises(MalformedPointError):
+            VerifyingKey.from_string(b('\x02') + enc)
+
+    def test_decoding_with_point_not_on_curve(self):
+        enc = b('\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3'
+                '\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4'
+                'z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*')
+
+        with self.assertRaises(MalformedPointError):
+            VerifyingKey.from_string(enc[:47] + b('\x00'))
+
+    def test_decoding_with_point_at_infinity(self):
+        # decoding it is unsupported, as it's not necessary to encode it
+        with self.assertRaises(MalformedPointError):
+            VerifyingKey.from_string(b('\x00'))
+
+    def test_from_string_with_invalid_curve_too_short_ver_key_len(self):
+        # both verifying_key_length and baselen are calculated internally
+        # by the Curve constructor, but since we depend on them verify
+        # that inconsistent values are detected
+        curve = Curve("test", ecdsa.curve_192, ecdsa.generator_192, (1, 2))
+        curve.verifying_key_length = 16
+        curve.baselen = 32
+
+        with self.assertRaises(MalformedPointError):
+            VerifyingKey.from_string(b('\x00')*16, curve)
+
+    def test_from_string_with_invalid_curve_too_long_ver_key_len(self):
+        # both verifying_key_length and baselen are calculated internally
+        # by the Curve constructor, but since we depend on them verify
+        # that inconsistent values are detected
+        curve = Curve("test", ecdsa.curve_192, ecdsa.generator_192, (1, 2))
+        curve.verifying_key_length = 16
+        curve.baselen = 16
+
+        with self.assertRaises(MalformedPointError):
+            VerifyingKey.from_string(b('\x00')*16, curve)
+
 
 class OpenSSL(unittest.TestCase):
     # test interoperability with OpenSSL tools. Note that openssl's ECDSA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ecdsa-0.13.2/ecdsa/util.py 
new/ecdsa-0.13.3/ecdsa/util.py
--- old/ecdsa-0.13.2/ecdsa/util.py      2019-04-17 21:23:20.000000000 +0200
+++ new/ecdsa-0.13.3/ecdsa/util.py      2019-10-07 15:51:57.000000000 +0200
@@ -216,18 +216,38 @@
     return sigencode_der(r, s, order)
 
 
+class MalformedSignature(Exception):
+    pass
+
+
 def sigdecode_string(signature, order):
     l = orderlen(order)
-    assert len(signature) == 2*l, (len(signature), 2*l)
+    if not len(signature) == 2 * l:
+        raise MalformedSignature(
+                "Invalid length of signature, expected {0} bytes long, "
+                "provided string is {1} bytes long"
+                .format(2 * l, len(signature)))
     r = string_to_number_fixedlen(signature[:l], order)
     s = string_to_number_fixedlen(signature[l:], order)
     return r, s
 
 def sigdecode_strings(rs_strings, order):
+    if not len(rs_strings) == 2:
+        raise MalformedSignature(
+                "Invalid number of strings provided: {0}, expected 2"
+                .format(len(rs_strings)))
     (r_str, s_str) = rs_strings
     l = orderlen(order)
-    assert len(r_str) == l, (len(r_str), l)
-    assert len(s_str) == l, (len(s_str), l)
+    if not len(r_str) == l:
+        raise MalformedSignature(
+                "Invalid length of first string ('r' parameter), "
+                "expected {0} bytes long, provided string is {1} bytes long"
+                .format(l, len(r_str)))
+    if not len(s_str) == l:
+        raise MalformedSignature(
+                "Invalid length of second string ('s' parameter), "
+                "expected {0} bytes long, provided string is {1} bytes long"
+                .format(l, len(s_str)))
     r = string_to_number_fixedlen(r_str, order)
     s = string_to_number_fixedlen(s_str, order)
     return r, s


Reply via email to