Skip to content

Commit

Permalink
Add support for Edwards curve keys, some cleanup of the SPKI decoder …
Browse files Browse the repository at this point in the history
…logic
  • Loading branch information
CBonnell committed Nov 20, 2024
1 parent 7c6dc64 commit b66d0c9
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 26 deletions.
43 changes: 25 additions & 18 deletions pkilint/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
NamedTuple,
)

from pyasn1.codec.der.decoder import decode
from pyasn1.codec.der.encoder import encode
from pyasn1.error import PyAsn1Error
from pyasn1.type.base import Asn1Type
from pyasn1.type.univ import (
Expand Down Expand Up @@ -302,6 +300,22 @@ def __str__(self):
return message


def create_and_append_node_from_pdu(
source_document: Document,
pdu: Asn1Type,
parent_node: Optional[PDUNode] = None,
):
child_node_name = get_node_name_for_pdu(pdu)

node = PDUNode(source_document, child_node_name, pdu, parent_node)

if parent_node is not None:
parent_node.children[child_node_name] = node
logger.debug("Appended %s node to %s", node.name, parent_node.path)

return node


def decode_substrate(
source_document: Document,
substrate: bytes,
Expand All @@ -319,24 +333,14 @@ def decode_substrate(
source_document, pdu_instance, parent_node, str(e)
) from e

decoded_pdu_name = get_node_name_for_pdu(decoded)

node = PDUNode(source_document, decoded_pdu_name, decoded, parent_node)

if parent_node is not None:
parent_node.children[decoded_pdu_name] = node
logger.debug("Appended %s node to %s", node.name, parent_node.path)

return node
return create_and_append_node_from_pdu(source_document, decoded, parent_node)


class OptionalAsn1TypeWrapper(NamedTuple):
asn1_type: Asn1Type


class ValueDecoder:
_BITSTRING_SCHEMA_OBJ = BitString()

VALUE_NODE_ABSENT = object()

def __init__(
Expand All @@ -352,12 +356,17 @@ def __init__(
self.type_mappings = type_mappings.copy()
self.default = default

def filter_value(self, node, type_node, value_node, pdu_type):
if self._BITSTRING_SCHEMA_OBJ.isSuperTypeOf(value_node.pdu):
def retrieve_substrate(self, value_node):
if isinstance(value_node.pdu, BitString):
return value_node.pdu.asOctets()
else:
return value_node.pdu

def decode_value(self, node, type_node, value_node, pdu_type):
substrate = self.retrieve_substrate(value_node)

return decode_substrate(value_node.document, substrate, pdu_type, value_node)

def __call__(self, node):
type_node = node.navigate(self.type_path)

Expand Down Expand Up @@ -400,10 +409,8 @@ def __call__(self, node):
if pdu_type is self.VALUE_NODE_ABSENT or pdu_type is None:
return

value_octets = self.filter_value(node, type_node, value_node, pdu_type)

try:
decode_substrate(value_node.document, value_octets, pdu_type, value_node)
self.decode_value(node, type_node, value_node, pdu_type)
except SubstrateDecodingFailedError as e:
schema_name = pdu_type.__class__.__name__

Expand Down
25 changes: 17 additions & 8 deletions pkilint/pkix/certificate/certificate_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

from cryptography.hazmat.primitives import hashes
from pyasn1.codec.der.encoder import encode
from pyasn1.error import PyAsn1Error
from pyasn1.type import univ
from pyasn1_alt_modules import rfc5280, rfc5480
from pyasn1_alt_modules import rfc5280

from pkilint import validation, util, document
from pkilint.pkix.key import verify_signature
Expand All @@ -17,14 +18,22 @@ def __init__(self, *, type_mappings):
type_mappings=type_mappings,
)

def filter_value(self, node, type_node, value_node, pdu_type):
if isinstance(pdu_type, rfc5480.ECPoint):
# wrap the BIT STRING in an OCTET STRING
octet_str = univ.OctetString(value_node.pdu.asOctets())

return encode(octet_str)
def decode_value(self, node, type_node, value_node, pdu_type):
if isinstance(pdu_type, univ.OctetString):
# map the BIT STRING into an OCTET STRING
try:
pdu = pdu_type.clone(value=value_node.pdu.asOctets())
except PyAsn1Error as e:
# bubble up any constraint violations
raise document.SubstrateDecodingFailedError(
value_node.document, pdu_type, value_node, str(e)
)

return document.create_and_append_node_from_pdu(
value_node.document, pdu, value_node
)
else:
return super().filter_value(node, type_node, value_node, pdu_type)
return super().decode_value(node, type_node, value_node, pdu_type)


class SubjectPublicKeyDecodingValidator(validation.DecodingValidator):
Expand Down
12 changes: 12 additions & 0 deletions pkilint/pkix/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
rfc5480.id_ecPublicKey: rfc5480.ECPoint(),
rfc5480.id_ecDH: rfc5480.ECPoint(),
rfc5480.id_ecMQV: rfc5480.ECPoint(),
rfc8410.id_Ed448: univ.OctetString(),
rfc8410.id_Ed25519: univ.OctetString(),
rfc8410.id_X448: univ.OctetString(),
rfc8410.id_X25519: univ.OctetString(),
}

SUBJECT_KEY_PARAMETER_ALGORITHM_IDENTIFIER_MAPPINGS = {
Expand Down Expand Up @@ -65,6 +69,14 @@ def convert_spki_to_object(spki_node: PDUNode):
return ec.EllipticCurvePublicKey.from_encoded_point(
curve, spki_node.navigate("subjectPublicKey").pdu.asOctets()
)
elif key_type == rfc8410.id_Ed448:
return ed448.Ed448PublicKey.from_public_bytes(
spki_node.navigate("subjectPublicKey").pdu.asOctets()
)
elif key_type == rfc8410.id_Ed25519:
return ed25519.Ed25519PublicKey.from_public_bytes(
spki_node.navigate("subjectPublicKey").pdu.asOctets()
)

# TODO: others
return None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIIBtzCCAWmgAwIBAgITH59R65FuWGNFHoyc0N3iWesrXzAFBgMrZXAwWTENMAsG
A1UEChMESUVURjERMA8GA1UECxMITEFNUFMgV0cxNTAzBgNVBAMTLFNhbXBsZSBM
QU1QUyBFZDI1NTE5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MCAXDTIwMTIxNTIx
MzU0NFoYDzIwNTIxMjE1MjEzNTQ0WjBZMQ0wCwYDVQQKEwRJRVRGMREwDwYDVQQL
EwhMQU1QUyBXRzE1MDMGA1UEAxMsU2FtcGxlIExBTVBTIEVkMjU1MTkgQ2VydGlm
aWNhdGlvbiBBdXRob3JpdHkwKjAFBgMrZXADIQCEgUZ9yI/rkX/82DihqzVIZQZ+
RKE3URyp+eN2TxJDBKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwHQYDVR0OBBYEFGuilX26FJvkLQTRB6TRguQua4y1MAUGAytlcANBAFAJrlWo
QjzwT0ph7rXe023x3GaLPMXMwQI2Of+apkdG2mH9ID6PE1bu3gRRqIH5w2tyS+xF
Jw0ouxcJyAyXEQ4=
-----END CERTIFICATE-----

node_path,validator,severity,code,message
certificate.tbsCertificate.extensions.2.extnValue.subjectKeyIdentifier,SubjectKeyIdentifierValidator,NOTICE,pkix.unknown_subject_key_identifier_calculation_method,

0 comments on commit b66d0c9

Please sign in to comment.