Skip to content

Commit cb98429

Browse files
authored
Add support for Edwards curve keys, some cleanup of the SPKI decoder logic (#135)
1 parent 7c6dc64 commit cb98429

File tree

4 files changed

+69
-26
lines changed

4 files changed

+69
-26
lines changed

pkilint/document.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
NamedTuple,
1414
)
1515

16-
from pyasn1.codec.der.decoder import decode
17-
from pyasn1.codec.der.encoder import encode
1816
from pyasn1.error import PyAsn1Error
1917
from pyasn1.type.base import Asn1Type
2018
from pyasn1.type.univ import (
@@ -302,6 +300,22 @@ def __str__(self):
302300
return message
303301

304302

303+
def create_and_append_node_from_pdu(
304+
source_document: Document,
305+
pdu: Asn1Type,
306+
parent_node: Optional[PDUNode] = None,
307+
):
308+
child_node_name = get_node_name_for_pdu(pdu)
309+
310+
node = PDUNode(source_document, child_node_name, pdu, parent_node)
311+
312+
if parent_node is not None:
313+
parent_node.children[child_node_name] = node
314+
logger.debug("Appended %s node to %s", node.name, parent_node.path)
315+
316+
return node
317+
318+
305319
def decode_substrate(
306320
source_document: Document,
307321
substrate: bytes,
@@ -319,24 +333,14 @@ def decode_substrate(
319333
source_document, pdu_instance, parent_node, str(e)
320334
) from e
321335

322-
decoded_pdu_name = get_node_name_for_pdu(decoded)
323-
324-
node = PDUNode(source_document, decoded_pdu_name, decoded, parent_node)
325-
326-
if parent_node is not None:
327-
parent_node.children[decoded_pdu_name] = node
328-
logger.debug("Appended %s node to %s", node.name, parent_node.path)
329-
330-
return node
336+
return create_and_append_node_from_pdu(source_document, decoded, parent_node)
331337

332338

333339
class OptionalAsn1TypeWrapper(NamedTuple):
334340
asn1_type: Asn1Type
335341

336342

337343
class ValueDecoder:
338-
_BITSTRING_SCHEMA_OBJ = BitString()
339-
340344
VALUE_NODE_ABSENT = object()
341345

342346
def __init__(
@@ -352,12 +356,17 @@ def __init__(
352356
self.type_mappings = type_mappings.copy()
353357
self.default = default
354358

355-
def filter_value(self, node, type_node, value_node, pdu_type):
356-
if self._BITSTRING_SCHEMA_OBJ.isSuperTypeOf(value_node.pdu):
359+
def retrieve_substrate(self, value_node):
360+
if isinstance(value_node.pdu, BitString):
357361
return value_node.pdu.asOctets()
358362
else:
359363
return value_node.pdu
360364

365+
def decode_value(self, node, type_node, value_node, pdu_type):
366+
substrate = self.retrieve_substrate(value_node)
367+
368+
return decode_substrate(value_node.document, substrate, pdu_type, value_node)
369+
361370
def __call__(self, node):
362371
type_node = node.navigate(self.type_path)
363372

@@ -400,10 +409,8 @@ def __call__(self, node):
400409
if pdu_type is self.VALUE_NODE_ABSENT or pdu_type is None:
401410
return
402411

403-
value_octets = self.filter_value(node, type_node, value_node, pdu_type)
404-
405412
try:
406-
decode_substrate(value_node.document, value_octets, pdu_type, value_node)
413+
self.decode_value(node, type_node, value_node, pdu_type)
407414
except SubstrateDecodingFailedError as e:
408415
schema_name = pdu_type.__class__.__name__
409416

pkilint/pkix/certificate/certificate_key.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
from cryptography.hazmat.primitives import hashes
44
from pyasn1.codec.der.encoder import encode
5+
from pyasn1.error import PyAsn1Error
56
from pyasn1.type import univ
6-
from pyasn1_alt_modules import rfc5280, rfc5480
7+
from pyasn1_alt_modules import rfc5280
78

89
from pkilint import validation, util, document
910
from pkilint.pkix.key import verify_signature
@@ -17,14 +18,22 @@ def __init__(self, *, type_mappings):
1718
type_mappings=type_mappings,
1819
)
1920

20-
def filter_value(self, node, type_node, value_node, pdu_type):
21-
if isinstance(pdu_type, rfc5480.ECPoint):
22-
# wrap the BIT STRING in an OCTET STRING
23-
octet_str = univ.OctetString(value_node.pdu.asOctets())
24-
25-
return encode(octet_str)
21+
def decode_value(self, node, type_node, value_node, pdu_type):
22+
if isinstance(pdu_type, univ.OctetString):
23+
# map the BIT STRING into an OCTET STRING
24+
try:
25+
pdu = pdu_type.clone(value=value_node.pdu.asOctets())
26+
except PyAsn1Error as e:
27+
# bubble up any constraint violations
28+
raise document.SubstrateDecodingFailedError(
29+
value_node.document, pdu_type, value_node, str(e)
30+
)
31+
32+
return document.create_and_append_node_from_pdu(
33+
value_node.document, pdu, value_node
34+
)
2635
else:
27-
return super().filter_value(node, type_node, value_node, pdu_type)
36+
return super().decode_value(node, type_node, value_node, pdu_type)
2837

2938

3039
class SubjectPublicKeyDecodingValidator(validation.DecodingValidator):

pkilint/pkix/key.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
rfc5480.id_ecPublicKey: rfc5480.ECPoint(),
1919
rfc5480.id_ecDH: rfc5480.ECPoint(),
2020
rfc5480.id_ecMQV: rfc5480.ECPoint(),
21+
rfc8410.id_Ed448: univ.OctetString(),
22+
rfc8410.id_Ed25519: univ.OctetString(),
23+
rfc8410.id_X448: univ.OctetString(),
24+
rfc8410.id_X25519: univ.OctetString(),
2125
}
2226

2327
SUBJECT_KEY_PARAMETER_ALGORITHM_IDENTIFIER_MAPPINGS = {
@@ -65,6 +69,14 @@ def convert_spki_to_object(spki_node: PDUNode):
6569
return ec.EllipticCurvePublicKey.from_encoded_point(
6670
curve, spki_node.navigate("subjectPublicKey").pdu.asOctets()
6771
)
72+
elif key_type == rfc8410.id_Ed448:
73+
return ed448.Ed448PublicKey.from_public_bytes(
74+
spki_node.navigate("subjectPublicKey").pdu.asOctets()
75+
)
76+
elif key_type == rfc8410.id_Ed25519:
77+
return ed25519.Ed25519PublicKey.from_public_bytes(
78+
spki_node.navigate("subjectPublicKey").pdu.asOctets()
79+
)
6880

6981
# TODO: others
7082
return None
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIBtzCCAWmgAwIBAgITH59R65FuWGNFHoyc0N3iWesrXzAFBgMrZXAwWTENMAsG
3+
A1UEChMESUVURjERMA8GA1UECxMITEFNUFMgV0cxNTAzBgNVBAMTLFNhbXBsZSBM
4+
QU1QUyBFZDI1NTE5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MCAXDTIwMTIxNTIx
5+
MzU0NFoYDzIwNTIxMjE1MjEzNTQ0WjBZMQ0wCwYDVQQKEwRJRVRGMREwDwYDVQQL
6+
EwhMQU1QUyBXRzE1MDMGA1UEAxMsU2FtcGxlIExBTVBTIEVkMjU1MTkgQ2VydGlm
7+
aWNhdGlvbiBBdXRob3JpdHkwKjAFBgMrZXADIQCEgUZ9yI/rkX/82DihqzVIZQZ+
8+
RKE3URyp+eN2TxJDBKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
9+
AQYwHQYDVR0OBBYEFGuilX26FJvkLQTRB6TRguQua4y1MAUGAytlcANBAFAJrlWo
10+
QjzwT0ph7rXe023x3GaLPMXMwQI2Of+apkdG2mH9ID6PE1bu3gRRqIH5w2tyS+xF
11+
Jw0ouxcJyAyXEQ4=
12+
-----END CERTIFICATE-----
13+
14+
node_path,validator,severity,code,message
15+
certificate.tbsCertificate.extensions.2.extnValue.subjectKeyIdentifier,SubjectKeyIdentifierValidator,NOTICE,pkix.unknown_subject_key_identifier_calculation_method,

0 commit comments

Comments
 (0)