@@ -511,8 +511,54 @@ def _smime_signed_decode(data: bytes) -> tuple[bytes | None, bytes]:
511511 raise ValueError ("Not an S/MIME signed message" )
512512
513513
514+ def get_smime_x509_extension_policies () -> tuple [
515+ ExtensionPolicy , ExtensionPolicy
516+ ]:
517+ """
518+ Gets the default X.509 extension policy for S/MIME. Some specifications
519+ that differ from the standard ones:
520+ - Certificates used as end entities (i.e., the cert used to sign
521+ a PKCS#7/SMIME message) should not have ca=true in their basic
522+ constraints extension.
523+ - EKU_CLIENT_AUTH_OID is not required
524+ - EKU_EMAIL_PROTECTION_OID is required
525+ """
526+
527+ # CA policy
528+ def _validate_ca (
529+ policy : Policy , cert : Certificate , bc : x509 .BasicConstraints
530+ ):
531+ assert not bc .ca
532+
533+ ca_policy = ExtensionPolicy .permit_all ().require_present (
534+ x509 .BasicConstraints ,
535+ Criticality .AGNOSTIC ,
536+ _validate_ca ,
537+ )
538+
539+ # EE policy
540+ def _validate_eku (
541+ policy : Policy , cert : Certificate , eku : x509 .ExtendedKeyUsage
542+ ):
543+ # Checking for EKU_EMAIL_PROTECTION_OID
544+ assert x509 .ExtendedKeyUsageOID .EMAIL_PROTECTION in eku # type: ignore[attr-defined]
545+
546+ ee_policy = ExtensionPolicy .permit_all ().require_present (
547+ x509 .ExtendedKeyUsage ,
548+ Criticality .AGNOSTIC ,
549+ _validate_eku ,
550+ )
551+
552+ return ca_policy , ee_policy
553+
554+
514555def _verify_pkcs7_certificates (certificates : list [x509 .Certificate ]) -> None :
515- builder = PolicyBuilder ().store (Store (certificates ))
556+ builder = (
557+ PolicyBuilder ()
558+ .store (Store (certificates ))
559+ .extension_policies (* get_smime_x509_extension_policies ())
560+ )
561+
516562 verifier = builder .build_client_verifier ()
517563 verifier .verify (certificates [0 ], certificates [1 :])
518564
0 commit comments