|
|
|
@ -6,6 +6,9 @@ import logging
|
|
|
|
|
import struct
|
|
|
|
|
|
|
|
|
|
import ecdsa
|
|
|
|
|
import ed25519
|
|
|
|
|
|
|
|
|
|
from trezor_agent.util import num2bytes
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
@ -86,6 +89,10 @@ def split_bits(value, *bits):
|
|
|
|
|
assert value == 0
|
|
|
|
|
return reversed(result)
|
|
|
|
|
|
|
|
|
|
SUPPORTED_CURVES = {
|
|
|
|
|
b'\x2A\x86\x48\xCE\x3D\x03\x01\x07': 'nist256p1',
|
|
|
|
|
b'\x2B\x06\x01\x04\x01\xDA\x47\x0F\x01': 'ed25519',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Parser(object):
|
|
|
|
|
def __init__(self, stream, to_hash=None):
|
|
|
|
@ -168,13 +175,38 @@ class Parser(object):
|
|
|
|
|
# https://tools.ietf.org/html/rfc6637#section-11
|
|
|
|
|
oid_size = stream.readfmt('B')
|
|
|
|
|
oid = stream.read(oid_size)
|
|
|
|
|
assert oid == b'\x2A\x86\x48\xCE\x3D\x03\x01\x07' # NIST P-256
|
|
|
|
|
assert oid in SUPPORTED_CURVES
|
|
|
|
|
curve_name = SUPPORTED_CURVES[oid]
|
|
|
|
|
|
|
|
|
|
mpi = parse_mpi(stream)
|
|
|
|
|
log.debug('mpi: %x', mpi)
|
|
|
|
|
prefix, x, y = split_bits(mpi, 4, 256, 256)
|
|
|
|
|
assert prefix == 4
|
|
|
|
|
p['point'] = (x, y)
|
|
|
|
|
log.debug('mpi: %x (%d bits)', mpi, mpi.bit_length())
|
|
|
|
|
if curve_name == 'nist256p1':
|
|
|
|
|
prefix, x, y = split_bits(mpi, 4, 256, 256)
|
|
|
|
|
assert prefix == 4
|
|
|
|
|
point = ecdsa.ellipticcurve.Point(curve=ecdsa.NIST256p.curve,
|
|
|
|
|
x=x, y=y)
|
|
|
|
|
vk = ecdsa.VerifyingKey.from_public_point(
|
|
|
|
|
point=point, curve=ecdsa.curves.NIST256p,
|
|
|
|
|
hashfunc=hashlib.sha256)
|
|
|
|
|
|
|
|
|
|
def _nist256p1_verify(signature, digest):
|
|
|
|
|
vk.verify_digest(signature=signature,
|
|
|
|
|
digest=digest,
|
|
|
|
|
sigdecode=lambda rs, order: rs)
|
|
|
|
|
p['verifier'] = _nist256p1_verify
|
|
|
|
|
elif curve_name == 'ed25519':
|
|
|
|
|
prefix, value = split_bits(mpi, 8, 256)
|
|
|
|
|
assert prefix == 0x40
|
|
|
|
|
vk = ed25519.VerifyingKey(num2bytes(value, size=32))
|
|
|
|
|
|
|
|
|
|
def _ed25519_verify(signature, digest):
|
|
|
|
|
sig = b''.join(num2bytes(val, size=32)
|
|
|
|
|
for val in signature)
|
|
|
|
|
vk.verify(sig, digest)
|
|
|
|
|
p['verifier'] = _ed25519_verify
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError('unsupported curve {}'.format(curve_name))
|
|
|
|
|
|
|
|
|
|
assert not stream.read()
|
|
|
|
|
|
|
|
|
|
# https://tools.ietf.org/html/rfc4880#section-12.2
|
|
|
|
@ -234,16 +266,9 @@ def load_public_key(stream):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify_digest(pubkey, digest, signature, label):
|
|
|
|
|
coords = pubkey['point']
|
|
|
|
|
point = ecdsa.ellipticcurve.Point(curve=ecdsa.NIST256p.curve,
|
|
|
|
|
x=coords[0], y=coords[1])
|
|
|
|
|
v = ecdsa.VerifyingKey.from_public_point(point=point,
|
|
|
|
|
curve=ecdsa.curves.NIST256p,
|
|
|
|
|
hashfunc=hashlib.sha256)
|
|
|
|
|
verifier = pubkey['verifier']
|
|
|
|
|
try:
|
|
|
|
|
v.verify_digest(signature=signature,
|
|
|
|
|
digest=digest,
|
|
|
|
|
sigdecode=lambda rs, order: rs)
|
|
|
|
|
verifier(signature, digest)
|
|
|
|
|
log.debug('%s is OK', label)
|
|
|
|
|
except ecdsa.keys.BadSignatureError:
|
|
|
|
|
log.error('Bad %s!', label)
|
|
|
|
|