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

RFC5280 Extension PrivateKeyUsagePeriod detected as UnrecognizedExtension #11195

Open
ricardo-reis-1970 opened this issue Jul 4, 2024 · 8 comments
Labels

Comments

@ricardo-reis-1970
Copy link

  • Versions of Python, cryptography, cffi, pip, and setuptools
    you're using
    I'm working on a Linux machine with:
Package       Version
------------- -------
cffi          1.16.0
cryptography  42.0.8
pip           24.1.1
setuptools    70.2.0

Platform      Version
------------- -------
Ubuntu        24.04
Python        3.12.3
  • How you installed cryptography
    pip install cryptography

  • Clear steps for reproducing your bug
    I have a CSCA certificate. When I parse it in the command-line, it looks like this:

$ openssl x509 -in CSCA.cer -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            [...]
        Signature Algorithm: ecdsa-with-SHA256
        [...]
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                [...]
            X509v3 Issuer Alternative Name: 
                [...]
            X509v3 Basic Constraints: critical
                [...]
            X509v3 Key Usage: critical
                [...]
            X509v3 Private Key Usage Period: 
                [...]
            X509v3 Subject Key Identifier: 
                [...]
            X509v3 Authority Key Identifier: 
                [...]
            X509v3 CRL Distribution Points: 
                [...]
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        [...]

As you can see, extension[4] comes out as Private Key Usage Period, as per RFC5280. It is not a specific ICAO extension.

However, when I load the exact same file via Python:

def get_cert_data(file):
    with open(file, 'r') as pem_file:
        pem_data = pem_file.read()
        if pem_data.startswith('-----BEGIN CERTIFICATE-----'):
            cert = x509.load_pem_x509_certificate(str.encode(pem_data), default_backend())
            return cert
        else:
            pass

csca = get_cert_data('Certificates/CSCA.cer')

then the output of an interactive session is this:

>>> pp(list(map(lambda e: e.value.__class__.__name__, csca.extensions)))
['SubjectAlternativeName',
 'IssuerAlternativeName',
 'BasicConstraints',
 'KeyUsage',
 'UnrecognizedExtension',
 'SubjectKeyIdentifier',
 'AuthorityKeyIdentifier',
 'CRLDistributionPoints']
>>> csca.extensions[4].oid
<ObjectIdentifier(oid=2.5.29.16, name=Unknown OID)>
>>> csca.extensions[4].value
<UnrecognizedExtension(oid=<ObjectIdentifier(oid=2.5.29.16, name=Unknown OID)>, value=b'0"\x80\x0f20221114114914Z\x81\x0f20251114114914Z')>

Both the extension and its very standard OID 2.5.29.16 are unrecognised!

Looking into the code, this is obvious, as both are absent from the relevant files:

# hazmat/_oid.py
class ExtensionOID:
    SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9")
    SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14")
    KEY_USAGE = ObjectIdentifier("2.5.29.15")
    SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17")
    ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18")
    BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
    NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30")
    CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31")
    CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32")
    POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33")
    AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35")
    POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36")
    EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37")
    FRESHEST_CRL = ObjectIdentifier("2.5.29.46")
    INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54")
    ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28")
    AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1")
    SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11")
    OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
    TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24")
    CRL_NUMBER = ObjectIdentifier("2.5.29.20")
    DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27")
    PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier(
        "1.3.6.1.4.1.11129.2.4.2"
    )
    PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3")
    SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5")
    MS_CERTIFICATE_TEMPLATE = ObjectIdentifier("1.3.6.1.4.1.311.21.7")
$ grep "^class" x509/extensions.py 
class DuplicateExtension(Exception):
class ExtensionNotFound(Exception):
class ExtensionType(metaclass=abc.ABCMeta):
class Extensions:
class CRLNumber(ExtensionType):
class AuthorityKeyIdentifier(ExtensionType):
class SubjectKeyIdentifier(ExtensionType):
class AuthorityInformationAccess(ExtensionType):
class SubjectInformationAccess(ExtensionType):
class AccessDescription:
class BasicConstraints(ExtensionType):
class DeltaCRLIndicator(ExtensionType):
class CRLDistributionPoints(ExtensionType):
class FreshestCRL(ExtensionType):
class DistributionPoint:
class ReasonFlags(utils.Enum):
class PolicyConstraints(ExtensionType):
class CertificatePolicies(ExtensionType):
class PolicyInformation:
class UserNotice:
class NoticeReference:
class ExtendedKeyUsage(ExtensionType):
class OCSPNoCheck(ExtensionType):
class PrecertPoison(ExtensionType):
class TLSFeature(ExtensionType):
class TLSFeatureType(utils.Enum):
class InhibitAnyPolicy(ExtensionType):
class KeyUsage(ExtensionType):
class NameConstraints(ExtensionType):
class Extension(typing.Generic[ExtensionTypeVar]):
class GeneralNames:
class SubjectAlternativeName(ExtensionType):
class IssuerAlternativeName(ExtensionType):
class CertificateIssuer(ExtensionType):
class CRLReason(ExtensionType):
class InvalidityDate(ExtensionType):
class PrecertificateSignedCertificateTimestamps(ExtensionType):
class SignedCertificateTimestamps(ExtensionType):
class OCSPNonce(ExtensionType):
class OCSPAcceptableResponses(ExtensionType):
class IssuingDistributionPoint(ExtensionType):
class MSCertificateTemplate(ExtensionType):
class UnrecognizedExtension(ExtensionType):

Is there a reason for having this particular RFC5280 extension left out?

@alex
Copy link
Member

alex commented Jul 4, 2024 via email

@ricardo-reis-1970
Copy link
Author

Well, the use case is ICAO certificates, which are the very core of what my company — Tegona SA — does.

As for the request, here it is:

Dear cryptography developers,

I would like to humbly request that you added the PrivateKeyUsagePeriod extension to your x509 module. From what little I could see from inspecting the source code, I am convinced that for you this would be a small step, but for my company and I this would mean a lot.

On a separate train of thought, I'd like to open the floor to the possibility that one could add extensions to the ones delivered by you, not in a "hacky" way but perhaps in a more structured manner, via some sort of call. The reason I mention this is that for now I could not detect any other missing extension from RFC5280, but I fear more would come up in the near future and we'd be meeting in similar circumstances. Further to this, we are liable to find in days to come bespoke extensions outside the norm.

Quite aware that you work selflessly for us, the Community at large, I hereby leave my deepest thanks in advance, hoping to continue benefitting from your excellent work, while remaining at your disposal for any and all enquiries regarding this subject.

Kind regards,
Ricardo

@alex
Copy link
Member

alex commented Jul 4, 2024 via email

@ricardo-reis-1970
Copy link
Author

Hi Alex,

That's a great suggestion! I'll have a stab at it, although git tends to be a bit of an incline for me to climb (Yeah, I'm old!).

I think I "kinda sorta" know what to do. I'll get back to you with either a pull request or a desperate cry for help. Give me the weekend.

@alex alex added the x509 label Jul 5, 2024
@HamdaanAliQuatil
Copy link

Hey @ricardo-reis-1970 👋 Can I probably lend a hand in this? I'd love to help

@ricardo-reis-1970
Copy link
Author

Hi @HamdaanAliQuatil. I would like to ask "What are you waiting for?", but I don't want to sound rude. Let me instead try a shorter "Yes, please." with a big "Thank you very much!" on the side.

Truth is, I am not quite confortable with OOP and it's all classes in there. Plus, I fear I might introduce noise, as these digital certificates theme is a bit news to me.

Again, thank you very much!

@HamdaanAliQuatil
Copy link

@alex I've created a WIP PR. I've read the contribution guidelines, which mention that unit tests accompany every feature to increase coverage. I'm trying to wrap my head around the existing tests and will see how/ where to add another one for this. Can you please confirm if this PR needs a unit test?

Another issue - I wanted to do a manual testing with x509 v3 cert but I'm unable to create a cert with the PrivateKeyUsagePeriod extension using openssl. I've described the issue in detail here.

Can you please let me know what am I doing wrong?

@alex
Copy link
Member

alex commented Jul 10, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

3 participants