Skip to content

Commit

Permalink
Merge e67c663 into 4c92d31
Browse files Browse the repository at this point in the history
  • Loading branch information
tomato42 committed Oct 24, 2019
2 parents 4c92d31 + e67c663 commit fee6b74
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 54 deletions.
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -78,16 +78,16 @@ 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^
# 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 -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
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 -sr
fi
Expand All @@ -98,11 +98,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
Expand Down
38 changes: 38 additions & 0 deletions src/ecdsa/_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Common functions for providing cross-python version compatibility.
"""
import sys
from six import integer_types


def str_idx_as_int(string, index):
"""Take index'th byte from string, return as integer"""
val = string[index]
if isinstance(val, integer_types):
return val
return ord(val)


if sys.version_info < (3, 0):
def normalise_bytes(buffer_object):
"""Cast the input into array of bytes."""
return buffer(buffer_object)

def hmac_compat(ret):
return ret

else:
if sys.version_info < (3, 4):
# on python 3.3 hmac.hmac.update() accepts only bytes, on newer
# versions it does accept memoryview() also
def hmac_compat(data):
if not isinstance(data, bytes):
return bytes(data)
return data
else:
def hmac_compat(data):
return data

def normalise_bytes(buffer_object):
"""Cast the input into array of bytes."""
return memoryview(buffer_object).cast('B')
49 changes: 22 additions & 27 deletions src/ecdsa/der.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import binascii
import base64
import warnings
from six import int2byte, b, integer_types, text_type
from six import int2byte, b, text_type
from ._compat import str_idx_as_int


class UnexpectedDER(Exception):
Expand All @@ -20,7 +21,7 @@ def encode_integer(r):
if len(h) % 2:
h = b("0") + h
s = binascii.unhexlify(h)
num = s[0] if isinstance(s[0], integer_types) else ord(s[0])
num = str_idx_as_int(s, 0)
if num <= 0x7f:
return b("\x02") + int2byte(len(s)) + s
else:
Expand Down Expand Up @@ -83,7 +84,7 @@ def encode_bitstring(s, unused=_sentry):
if unused:
if not s:
raise ValueError("unused is non-zero but s is empty")
last = s[-1] if isinstance(s[-1], integer_types) else ord(s[-1])
last = str_idx_as_int(s, -1)
if last & (2 ** unused - 1):
raise ValueError("unused bits must be zeros in DER")
encoded_unused = int2byte(unused)
Expand Down Expand Up @@ -121,7 +122,7 @@ def encode_number(n):


def remove_constructed(string):
s0 = string[0] if isinstance(string[0], integer_types) else ord(string[0])
s0 = str_idx_as_int(string, 0)
if (s0 & 0xe0) != 0xa0:
raise UnexpectedDER("wanted type 'constructed tag' (0xa0-0xbf), "
"got 0x%02x" % s0)
Expand All @@ -135,9 +136,8 @@ def remove_constructed(string):
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])
if string[:1] != b"\x30":
n = str_idx_as_int(string, 0)
raise UnexpectedDER("wanted type 'sequence' (0x30), got 0x%02x" % n)
length, lengthlength = read_length(string[1:])
if length > len(string) - 1 - lengthlength:
Expand All @@ -147,8 +147,8 @@ def remove_sequence(string):


def remove_octet_string(string):
if not string.startswith(b("\x04")):
n = string[0] if isinstance(string[0], integer_types) else ord(string[0])
if string[:1] != b"\x04":
n = str_idx_as_int(string, 0)
raise UnexpectedDER("wanted type 'octetstring' (0x04), got 0x%02x" % n)
length, llen = read_length(string[1:])
body = string[1+llen:1+llen+length]
Expand All @@ -157,8 +157,8 @@ def remove_octet_string(string):


def remove_object(string):
if not string.startswith(b("\x06")):
n = string[0] if isinstance(string[0], integer_types) else ord(string[0])
if string[:1] != b"\x06":
n = str_idx_as_int(string, 0)
raise UnexpectedDER("wanted type 'object' (0x06), got 0x%02x" % n)
length, lengthlength = read_length(string[1:])
body = string[1+lengthlength:1+lengthlength+length]
Expand All @@ -180,9 +180,8 @@ 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])
if string[:1] != b"\x02":
n = str_idx_as_int(string, 0)
raise UnexpectedDER("wanted type 'integer' (0x02), got 0x%02x" % n)
length, llen = read_length(string[1:])
if length > len(string) - 1 - llen:
Expand All @@ -191,16 +190,14 @@ def remove_integer(string):
raise UnexpectedDER("0-byte long encoding of integer")
numberbytes = string[1+llen:1+llen+length]
rest = string[1+llen+length:]
msb = numberbytes[0] if isinstance(numberbytes[0], integer_types) \
else ord(numberbytes[0])
msb = str_idx_as_int(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])
smsb = str_idx_as_int(numberbytes, 1)
if smsb < 0x80:
raise UnexpectedDER("Invalid encoding of integer, unnecessary "
"zero padding bytes")
Expand All @@ -215,7 +212,7 @@ def read_number(string):
if llen > len(string):
raise UnexpectedDER("ran out of length bytes")
number = number << 7
d = string[llen] if isinstance(string[llen], integer_types) else ord(string[llen])
d = str_idx_as_int(string, llen)
number += (d & 0x7f)
llen += 1
if not d & 0x80:
Expand All @@ -238,7 +235,7 @@ def encode_length(l):
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])
num = str_idx_as_int(string, 0)
if not (num & 0x80):
# short form
return (num & 0x7f), 1
Expand All @@ -250,7 +247,7 @@ def read_length(string):
if llen > len(string)-1:
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])
msb = str_idx_as_int(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
Expand Down Expand Up @@ -301,17 +298,16 @@ def remove_bitstring(string, expect_unused=_sentry):
warnings.warn("Legacy call convention used, expect_unused= needs to be"
" specified",
DeprecationWarning)
num = string[0] if isinstance(string[0], integer_types) else ord(string[0])
if not string.startswith(b("\x03")):
num = str_idx_as_int(string, 0)
if string[:1] != b"\x03":
raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" % num)
length, llen = read_length(string[1:])
if not length:
raise UnexpectedDER("Invalid length of bit string, can't be 0")
body = string[1+llen:1+llen+length]
rest = string[1+llen+length:]
if expect_unused is not _sentry:
unused = body[0] if isinstance(body[0], integer_types) \
else ord(body[0])
unused = str_idx_as_int(body, 0)
if not 0 <= unused <= 7:
raise UnexpectedDER("Invalid encoding of unused bits")
if expect_unused is not None and expect_unused != unused:
Expand All @@ -320,8 +316,7 @@ def remove_bitstring(string, expect_unused=_sentry):
if unused:
if not body:
raise UnexpectedDER("Invalid encoding of empty bit string")
last = body[-1] if isinstance(body[-1], integer_types) else \
ord(body[-1])
last = str_idx_as_int(body, -1)
# verify that all the unused bits are set to zero (DER requirement)
if last & (2 ** unused - 1):
raise UnexpectedDER("Non zero padding bits in bit string")
Expand Down
Loading

0 comments on commit fee6b74

Please sign in to comment.