Skip to content

Commit 04e1715

Browse files
committed
Add keyid to reference implementation.
1 parent ddb48b2 commit 04e1715

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

implementation/ecdsa.py

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ def sign(self, message: bytes) -> bytes:
2828
h = SHA256.new(message)
2929
return DSS.new(self.secret_key, 'deterministic-rfc6979').sign(h)
3030

31+
def keyid(self) -> str:
32+
"""Returns a fingerprint of the public key."""
33+
return Verifier(self.public_key).keyid()
34+
3135

3236
class Verifier:
3337
def __init__(self, public_key):
@@ -41,3 +45,10 @@ def verify(self, message: bytes, signature: bytes) -> bool:
4145
return True
4246
except ValueError:
4347
return False
48+
49+
def keyid(self) -> str:
50+
"""Returns a fingerprint of the public key."""
51+
# Note: This is a hack for demonstration purposes. A proper fingerprint
52+
# should be used.
53+
key = self.public_key.export_key(format='OpenSSH').encode('ascii')
54+
return SHA256.new(key).hexdigest()[:8]

implementation/signing_spec.py

+24-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
>>> pprint(json.loads(signature_json))
2727
{'payload': 'aGVsbG8gd29ybGQ=',
2828
'payloadType': 'http://example.com/HelloWorld',
29-
'signatures': [{'sig': 'A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=='}]}
29+
'signatures': [{'keyid': '66301bbf',
30+
'sig': 'A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=='}]}
3031
3132
Verification example:
3233
@@ -43,20 +44,28 @@
4344
import base64, binascii, dataclasses, json, struct
4445

4546
# Protocol requires Python 3.8+.
46-
from typing import Iterable, List, Protocol, Tuple
47+
from typing import Iterable, List, Optional, Protocol, Tuple
4748

4849

4950
class Signer(Protocol):
5051
def sign(self, message: bytes) -> bytes:
5152
"""Returns the signature of `message`."""
5253
...
5354

55+
def keyid(self) -> Optional[str]:
56+
"""Returns the ID of this key, or None if not supported."""
57+
...
58+
5459

5560
class Verifier(Protocol):
5661
def verify(self, message: bytes, signature: bytes) -> bool:
5762
"""Returns true if `message` was signed by `signature`."""
5863
...
5964

65+
def keyid(self) -> Optional[str]:
66+
"""Returns the ID of this key, or None if not supported."""
67+
...
68+
6069

6170
# Collection of verifiers, each of which is associated with a name.
6271
VerifierList = Iterable[Tuple[str, Verifier]]
@@ -88,14 +97,16 @@ def PAE(payloadType: str, payload: bytes) -> bytes:
8897

8998

9099
def Sign(payloadType: str, payload: bytes, signer: Signer) -> str:
100+
signature = {
101+
'keyid': signer.keyid(),
102+
'sig': b64enc(signer.sign(PAE(payloadType, payload))),
103+
}
104+
if not signature['keyid']:
105+
del signature['keyid']
91106
return json.dumps({
92-
'payload':
93-
b64enc(payload),
94-
'payloadType':
95-
payloadType,
96-
'signatures': [{
97-
'sig': b64enc(signer.sign(PAE(payloadType, payload)))
98-
}],
107+
'payload': b64enc(payload),
108+
'payloadType': payloadType,
109+
'signatures': [signature],
99110
})
100111

101112

@@ -107,6 +118,10 @@ def Verify(json_signature: str, verifiers: VerifierList) -> VerifiedPayload:
107118
recognizedSigners = []
108119
for signature in wrapper['signatures']:
109120
for name, verifier in verifiers:
121+
if (signature.get('keyid') is not None and
122+
verifier.keyid() is not None and
123+
signature.get('keyid') != verifier.keyid()):
124+
continue
110125
if verifier.verify(pae, b64dec(signature['sig'])):
111126
recognizedSigners.append(name)
112127
if not recognizedSigners:

0 commit comments

Comments
 (0)