Skip to content

Commit 046bf26

Browse files
committed
feat: safest cert handling
1 parent 24529cc commit 046bf26

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

pyeudiw/x509/verify.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def verify_x509_attestation_chain(x5c: list[bytes]) -> bool:
9090
if not _check_datetime(exp):
9191
return False
9292

93-
pems = [DER_cert_to_PEM_cert(cert) for cert in x5c]
93+
pems = [to_PEM_cert(cert) for cert in x5c]
9494

9595
return _verify_x509_certificate_chain(pems)
9696

@@ -149,8 +149,22 @@ def to_PEM_cert(cer: str | bytes) -> str:
149149
use it unless you do NOT hany prior way to know the actual representation
150150
format of a certificate
151151
"""
152-
raise NotImplementedError("TODO")
152+
cert_s = b""
153153

154+
if isinstance(cer, str):
155+
if is_pem_format(cer):
156+
return cer
157+
cert_s = cer.encode()
158+
else:
159+
cert_s = cer
160+
161+
if cert_s.startswith(b"-----BEGIN CERTIFICATE-----"):
162+
return str(cert_s)
163+
164+
if _BASE64_RE.fullmatch(str(cert_s)):
165+
return B64DER_cert_to_PEM_cert(cert_s)
166+
else:
167+
return DER_cert_to_PEM_cert(cert_s)
154168

155169
def pem_to_pems_list(cert: str) -> list[str]:
156170
"""
@@ -164,29 +178,31 @@ def pem_to_pems_list(cert: str) -> list[str]:
164178
"""
165179
return [str(cert) for cert in pem.parse(cert)]
166180

167-
def der_list_to_pem_list(der_list: list[bytes]) -> list[str]:
181+
def to_pem_list(der_list: list[bytes] | list[str]) -> list[str]:
168182
"""
169-
Convert the x509 certificate chain from DER to PEM.
183+
If the input is a list of DER certificates, it will be converted to a list of PEM certificates.
184+
If the input is a list of PEM certificates, it will be returned as is.
170185
171186
:param der: The x509 certificate chain in DER format
172187
:type der: list[bytes]
173188
174189
:returns: The x509 certificate chain in PEM format
175190
:rtype: list[str]
176191
"""
177-
return [DER_cert_to_PEM_cert(cert) for cert in der_list]
192+
return [to_PEM_cert(cert) for cert in der_list]
178193

179-
def pem_list_to_der_list(pem_list: list[str]) -> list[bytes]:
194+
def to_der_list(pem_list: list[str] | list[bytes]) -> list[bytes]:
180195
"""
181-
Convert the x509 certificate chain from PEM to DER.
196+
If the input is a list of PEM certificates, it will be converted to a list of DER certificates.
197+
If the input is a list of DER certificates, it will be returned as is.
182198
183199
:param pem_list: The x509 certificate chain in PEM format
184200
:type pem_list: list[str]
185201
186202
:returns: The x509 certificate chain in DER format
187203
:rtype: list[bytes]
188204
"""
189-
return [PEM_cert_to_DER_cert(cert) for cert in pem_list]
205+
return [to_DER_cert(cert) for cert in pem_list]
190206

191207
def get_expiry_date_from_x5c(x5c: list[bytes]) -> datetime:
192208
"""
@@ -211,7 +227,7 @@ def verify_x509_anchor(pem_str: str) -> bool:
211227
:returns: True if the x509 anchor certificate is valid else False
212228
:rtype: bool
213229
"""
214-
cert_data = load_der_x509_certificate(PEM_cert_to_DER_cert(pem_str))
230+
cert_data = load_der_x509_certificate(to_DER_cert(pem_str))
215231

216232
if not _check_datetime(cert_data.not_valid_after):
217233
logging.error(LOG_ERROR.format("check datetime failed"))
@@ -258,7 +274,7 @@ def get_issuer_from_x5c(x5c: list[bytes] | list[str]) -> Optional[str]:
258274
:returns: The issuer
259275
:rtype: str
260276
"""
261-
der = x5c[0] if isinstance(x5c[0], bytes) else PEM_cert_to_DER_cert(x5c[0])
277+
der = to_DER_cert(x5c[0])
262278
return get_get_subject_name(der)
263279

264280

@@ -272,7 +288,7 @@ def get_trust_anchor_from_x5c(x5c: list[bytes] | list[str]) -> Optional[str]:
272288
:returns: The issuer
273289
:rtype: str
274290
"""
275-
der = x5c[-1] if isinstance(x5c[-1], bytes) else PEM_cert_to_DER_cert(x5c[-1])
291+
der = to_DER_cert(x5c[-1])
276292
return get_get_subject_name(der)
277293

278294
def get_expiry_date_from_x5c(x5c: list[bytes] | list[str]) -> datetime:
@@ -285,7 +301,7 @@ def get_expiry_date_from_x5c(x5c: list[bytes] | list[str]) -> datetime:
285301
:returns: The expiry date
286302
:rtype: datetime
287303
"""
288-
der = x5c[0] if isinstance(x5c[0], bytes) else PEM_cert_to_DER_cert(x5c[0])
304+
der = to_DER_cert(x5c[0])
289305
cert = load_der_x509_certificate(der)
290306
return cert.not_valid_after
291307

@@ -303,7 +319,7 @@ def get_x509_info(cert: bytes | str, info_type: str = "x509_san_dns") -> str:
303319
"""
304320
get_common_name = lambda cert: cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
305321

306-
der = cert if isinstance(cert, bytes) else PEM_cert_to_DER_cert(cert)
322+
der = to_DER_cert(cert)
307323
cert: x509.Certificate = load_der_x509_certificate(der, default_backend())
308324

309325
try:
@@ -334,13 +350,29 @@ def is_der_format(cert: bytes) -> str:
334350
except crypto.Error as e:
335351
logging.error(LOG_ERROR.format(e))
336352
return False
353+
354+
def is_pem_format(cert: str) -> str:
355+
"""
356+
Check if the certificate is in PEM format.
337357
358+
:param cert: The certificate
359+
:type cert: bytes
360+
361+
:returns: True if the certificate is in PEM format else False
362+
:rtype: bool
363+
"""
364+
try:
365+
crypto.load_certificate(crypto.FILETYPE_PEM, cert)
366+
return True
367+
except crypto.Error as e:
368+
logging.error(LOG_ERROR.format(e))
369+
return False
338370

339371
def get_public_key_from_x509_chain(x5c: list[bytes]) -> ECKey | RSAKey | dict:
340372
raise NotImplementedError("TODO")
341373

342374
def get_certificate_type(cert: str | bytes) -> str:
343-
pem = cert if isinstance(cert, str) and cert.startswith("-----BEGIN CERTIFICATE-----") else DER_cert_to_PEM_cert(cert)
375+
pem = to_PEM_cert(cert)
344376

345377
cert = x509.load_pem_x509_certificate(pem.encode(), default_backend())
346378
public_key = cert.public_key()

0 commit comments

Comments
 (0)