Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PKCS#7 signing & verification - Certificate extension policies #12465

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

nitneuqr
Copy link
Contributor

As per #12267 and #12104, I'm opening this draft implementation of verification of PKCS#7 (S/MIME) certificates. Tests are not passing yet; still need to build an appropriate certificate for this.

The constraints I've gathered so far:

  • Certificates used as end entities (i.e., the cert used to sign
    a PKCS#7/SMIME message) should not have ca=true in their basic
    constraints extension.
  • EKU_CLIENT_AUTH_OID is not required
  • EKU_EMAIL_PROTECTION_OID is required

@alex @woodruffw @prauscher feel free to add some more constraints, I'm not particularly familiar with CA verification.

added tests accordingly
@nitneuqr
Copy link
Contributor Author

nitneuqr commented Feb 15, 2025

@alex wondering if there are best practices for certificates: better store it in vectors or dynamically create one during testing with the x509.CertificateBuilder?

@alex
Copy link
Member

alex commented Feb 15, 2025

Depends a bit on the use case. If you're verifying that we handle that certificate itself, it's better in vectors. If you're verifying something else either can work.

@nitneuqr
Copy link
Contributor Author

nitneuqr commented Feb 15, 2025

OK, I'll go with storing it in vectors then. Mostly doing it for coverage.

@prauscher
Copy link
Contributor

My excerpt from https://www.rfc-editor.org/rfc/rfc8550#section-4.4 would be:

  • SHOULD NOT contain basicConstraints (per RFC 5280)
  • if key Usage extension is present, MUST allow digitalSignature and/or nonRepudiation (if extensions is not present, this MUST be ignored)
  • subjectAltName (if used) MUST be encoded using rfc822Name (for ascii-addresses) or otherName (for non-ascii-addresses)
  • if extendedKeyUsage is present, it MUST allow id-kp-emailProtection or anyExtendedKeyUsage

Section 4.4.4 also discusses some limitations regarding certificates which may only be used for signing, but not for encryption - so maybe two separate policies (which would be quite similar) would be required?

do not know if a CA policy is needed!
@nitneuqr nitneuqr changed the title PKCS#7 certificate extension policies & verification PKCS#7 signing & verification - Certificate extension policies Feb 16, 2025
@nitneuqr
Copy link
Contributor Author

nitneuqr commented Feb 16, 2025

Hey, just pushed a first version of the constraints for certificates used as EE for email signing & verification.

Section 4.4.4 also discusses some limitations regarding certificates which may only be used for signing, but not for encryption - so maybe two separate policies (which would be quite similar) would be required?

I'd go for constraints linked to signing & verification for now, and address encryption / decryption later. I'm not sure openssl smime -decrypt checks anything in the certificates used, whereas it is the case for openssl smime -verify.

For the constraints, I have no experience with them, I'll implement what seems right w.r.t. RFC 😄

Also, I've left empty the CA constraints, I'm not sure what to fill as of now.

@prauscher
Copy link
Contributor

Not sure about the CA constraints either, from our company-certificate they include EMAIL_PROTECTION in EKU, but not sure if this is required. From this stackexchange-post I read that its application to ca-certificates is application-specific and not required by RFC. So for this use-case ignoring it in the CA might be the best thing (as long as other verifiers in cryptography do not have preference here).

From my view (but without deep knowledge about cryptography-inner-works, so feel free to correct me) I change a few parts:

  • according to https://docs.python.org/3/reference/simple_stmts.html#grammar-token-python-grammar-assert_stmt assert is ignored if __debug__ is False - should it be used for verification or am I missing something?
  • _validate_eku should probably allow for ANY_EXTENDED_KEY_USAGE too
  • Shouldn't ee_policy treat ExtendedKeyUsage as may_be_present in accordance to RFC 8550?
  • Shouldn't ee_policy include a may_be_presend check for a CRITICAL keyUsage, with an implementation of something like assert ku.digital_signature or ku.content_commitment # content_commitment used to be named non repudiation?

@nitneuqr
Copy link
Contributor Author

Totally agree with you @prauscher, for CA I'd either leave it as a .permit_all() or a .webpki_defaults_ca(). Any opinion on this is welcome 😄

For the changes, feel free to initiate a review, this is mostly draft as it blocks #12267. Good catches for the fixes, modifying the code now.

And I totally agree with the assert part, I've mostly copied what was done in other tests since there is not documentation on using validator callback in ExtensionPolicies yet. I'll change to raising a ValueError for now.

@nitneuqr
Copy link
Contributor Author

As per [RFC5280], certificates MUST contain a basicConstraints
extension in CA certificates and SHOULD NOT contain that extension in
end-entity certificates.

Since this is specified in https://www.rfc-editor.org/rfc/rfc8550#section-4.4, I'll go with .webpki_defaults_ca() which seems to be exactly what we need.

tests still to be implemented
@nitneuqr
Copy link
Contributor Author

First suggestions integrated, missing:

  • Testing with inappropriate certificates, for coverage
  • Handling the SubjectAlternativeName constraint defined here

@prauscher
Copy link
Contributor

prauscher commented Feb 18, 2025

For the subjectAlternativeName constraint we probably need to receive the mail address as a parameter of pkcs7_x509_extension_policies. After reading https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 I'd suggest something along the following:

def pkcs7_x509_extension_policies(mail_address: str):
    [...]
    def _validate_subject_alternative_name(policy, cert, san):
        if san is None:
            raise ValueError("Subject Alternative Name is required")

        if mail_address.split("@")[0].isascii():
            if mail_address.lower() not in [name.lower() for name in san.get_values_for_type(x509.RFC822Name)]:
                raise ValueError(f"Subject Alternative Name does not contain RFC822Name {mail_address}")

        else:
            if mail_address.lower() not in [name.value.lower() for name in san.get_values_for_type(x509.OtherName) if name.type_id == x509.ObjectIdentifier("1.3.6.1.5.5.7.8.9")]:
                raise ValueError(f"Subject Alternative Name does not contain OtherName {mail_address}")

@nitneuqr
Copy link
Contributor Author

Thanks for the code! I'm unsure about specifying all the time an email address in the extension policy. To me, it seems a bit too restrictive (?). Moreover, it seems that there are things checked already in default EE policies in cryptography:

Due to this, I'll pass to .webpki_defaults_ee().

To me, what we need to check from RFC 8550 is:

  • Check all the GeneralNames in SubjectAlternativeName
  • For those which are email addresses (contains @?), verify that the general parts stored in rfc822Name are ascii, and those stored in otherName are non-ascii

Also, checked RFC 5750 for S/MIME 3.2 (which we are currently supporting), and the differences are minor (such as the ASCII / non-ASCII differentiation). I suggest we go with RFC 8550 for that matter.

Will push a nearly final version in the following hours 😄

added SAN checking (incomplete though)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants