Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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