Skip to content

Commit c7de5b2

Browse files
committed
fix: complete verify chain on extract_and_update_trust_materials
1 parent 046bf26 commit c7de5b2

File tree

1 file changed

+50
-42
lines changed

1 file changed

+50
-42
lines changed

pyeudiw/trust/handler/x509.py

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
from pyeudiw.trust.handler.interface import TrustHandlerInterface
55
from pyeudiw.trust.model.trust_source import TrustSourceData, TrustEvaluationType
66
from pyeudiw.trust.handler.exceptions import InvalidTrustHandlerConfiguration
7-
from pyeudiw.jwk.parse import parse_pem, parse_x5c_keys, parse_certificate
7+
from pyeudiw.jwk.parse import parse_x5c_keys, parse_certificate
88
from cryptojwt.jwk.jwk import key_from_jwk_dict
99
from pyeudiw.x509.verify import (
1010
PEM_cert_to_B64DER_cert,
1111
to_DER_cert,
1212
verify_x509_attestation_chain,
1313
get_expiry_date_from_x5c,
14-
der_list_to_pem_list,
15-
pem_list_to_der_list,
14+
to_pem_list,
15+
to_der_list,
1616
get_x509_info,
1717
get_trust_anchor_from_x5c,
1818
get_certificate_type
@@ -94,7 +94,7 @@ def __init__(
9494
logger.error(f"Invalid x509 leaf certificate using CA {k}. Unmatching private key, the chain will be removed")
9595
continue
9696

97-
chain = pem_list_to_der_list(v) if type(v[0]) == str and v[0].startswith("-----BEGIN CERTIFICATE-----") else v
97+
chain = to_der_list(v)
9898

9999
if verify_x509_attestation_chain(chain):
100100
self.relying_party_certificate_chains_by_ca[k] = chain
@@ -104,14 +104,51 @@ def __init__(
104104

105105
self.private_keys = private_keys
106106

107+
def _verify_chain(self, x5c: list[str]) -> bool:
108+
"""
109+
Verify the x5c chain.
110+
:param x5c: The x5c chain to verify.
111+
:return: True if the chain is valid, False otherwise.
112+
"""
113+
der_chain = [to_DER_cert(cert) for cert in x5c]
114+
115+
if len(der_chain) > 1 and not verify_x509_attestation_chain(der_chain):
116+
logger.error(f"Invalid x509 certificate chain. Chain validation failed")
117+
return False
118+
119+
issuer = get_trust_anchor_from_x5c(der_chain)
120+
121+
if not issuer:
122+
logger.error("Invalid x509 certificate chain. Issuer not found")
123+
return False
124+
125+
if not issuer in self.certificate_authorities:
126+
logger.error("Invalid x509 certificate chain. Issuer not found in the list of trusted CAs")
127+
return False
128+
129+
issuer_cert = self.certificate_authorities[issuer]
130+
131+
try:
132+
issuer_jwk = parse_certificate(issuer_cert)
133+
chain_jwks = parse_x5c_keys(der_chain)
134+
except Exception as e:
135+
logger.error(f"Invalid x509 certificate chain. Parsing failed: {e}")
136+
return False
137+
138+
if not issuer_jwk.thumbprint == chain_jwks[-1].thumbprint:
139+
logger.error("Invalid x509 certificate chain. Issuer thumbprint does not match")
140+
return False
141+
142+
return True
143+
107144
def extract_and_update_trust_materials(
108145
self, issuer: str, trust_source: TrustSourceData
109146
) -> TrustSourceData:
110147
# Return the first valid chain
148+
111149
for ca, chain in self.relying_party_certificate_chains_by_ca.items():
112-
if not verify_x509_attestation_chain(chain):
113-
logger.error(f"Invalid x509 certificate chain using CA {ca}. Chain validation failed, the chain will be removed")
114-
del self.relying_party_certificate_chains_by_ca[ca]
150+
if not self._verify_chain(chain):
151+
logger.error(f"Invalid x509 certificate chain using CA {ca}. Chain will be ignored")
115152
continue
116153

117154
exp = get_expiry_date_from_x5c(chain)
@@ -120,7 +157,7 @@ def extract_and_update_trust_materials(
120157
X509Handler._TRUST_TYPE,
121158
TrustEvaluationType(
122159
attribute_name="x5c",
123-
x5c=der_list_to_pem_list(chain),
160+
x5c=to_pem_list(chain),
124161
expiration_date=exp,
125162
jwks=self.private_keys,
126163
trust_handler_name=self.name,
@@ -136,47 +173,18 @@ def validate_trust_material(
136173
x5c: list[str],
137174
trust_source: TrustSourceData,
138175
) -> tuple[bool, TrustSourceData]:
139-
# TODO: qui c'è del lavoro veramente sporco da fare.
140-
# Bisogna
141-
# (1) normalizzare la rappresentazione della chain a DER; per fare questo bisogna fare inferenza se PEM o Base64+DER
142-
# (2) normalizzare il salvatagggio della chain a PEM
143-
# (3) incrociare le dita che MDOC non si sfasci...
144-
der_chain = [to_DER_cert(cert) for cert in x5c]
145-
pem_chain = der_list_to_pem_list(der_chain)
146-
147-
if len(der_chain) > 1 and not verify_x509_attestation_chain(der_chain):
148-
logger.error(f"Invalid x509 certificate chain. Chain validation failed")
149-
return False, trust_source
150-
151-
issuer = get_trust_anchor_from_x5c(der_chain)
152-
153-
if not issuer:
154-
logger.error("Invalid x509 certificate chain. Issuer not found")
155-
return False, trust_source
156-
157-
if not issuer in self.certificate_authorities:
158-
logger.error("Invalid x509 certificate chain. Issuer not found in the list of trusted CAs")
159-
return False, trust_source
160-
161-
issuer_pem = self.certificate_authorities[issuer]
176+
chain_jwks = parse_x5c_keys(x5c)
177+
valid = self._verify_chain(x5c)
162178

163-
try:
164-
issuer_jwk = parse_pem(issuer_pem)
165-
chain_jwks = parse_x5c_keys(x5c)
166-
except Exception as e:
167-
logger.error("Invalid x509 certificate chain. Parsing failed: {e}")
168-
return False, trust_source
169-
170-
if not issuer_jwk.thumbprint == chain_jwks[-1].thumbprint:
171-
logger.error("Invalid x509 certificate chain. Issuer thumbprint does not match")
179+
if not valid:
172180
return False, trust_source
173181

174182
trust_source.add_trust_param(
175183
"x509",
176184
TrustEvaluationType(
177185
attribute_name=self.get_handled_trust_material_name(),
178-
x5c=pem_chain,
179-
expiration_date=get_expiry_date_from_x5c(der_chain),
186+
x5c=to_pem_list(x5c),
187+
expiration_date=get_expiry_date_from_x5c(x5c),
180188
jwks=chain_jwks,
181189
trust_handler_name=self.name,
182190
)

0 commit comments

Comments
 (0)