@@ -511,8 +511,54 @@ def _smime_signed_decode(data: bytes) -> tuple[bytes | None, bytes]:
511
511
raise ValueError ("Not an S/MIME signed message" )
512
512
513
513
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
+
514
555
def _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
+
516
562
verifier = builder .build_client_verifier ()
517
563
verifier .verify (certificates [0 ], certificates [1 :])
518
564
0 commit comments