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

CAI, OCSP and CDP as System.Uri #59305

Closed
amin1best opened this issue Sep 18, 2021 · 7 comments
Closed

CAI, OCSP and CDP as System.Uri #59305

amin1best opened this issue Sep 18, 2021 · 7 comments
Labels
area-System.Security question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@amin1best
Copy link

Hi,
X.509 Certificate has two fields, Authority Information Access (AIA) and CRL Distribution Points (CDP).
Authority Information Access field has two Access Methods called Certification Authority Issuer (CAI) and On-Line Certificate Status Protocol (OCSP).

All three of above are URLs.

How can I set or get these fields and access methods as System.Uri in System.Security.Cryptography.X509Certificates.X509Certificate2?

Is there a plan to support these two Extensions in High Level API?

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Security untriaged New issue has not been triaged by the area owner labels Sep 18, 2021
@ghost
Copy link

ghost commented Sep 18, 2021

Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq, @GrabYourPitchforks
See info in area-owners.md if you want to be subscribed.

Issue Details

Hi,
X.509 Certificate has two fields, Authority Information Access (AIA) and CRL Distribution Points (CDP).
Authority Information Access field has two Access Methods called Certification Authority Issuer (CAI) and On-Line Certificate Status Protocol (OCSP).

All three of above are URLs.

How can I set or get these fields and access methods as System.Uri in System.Security.Cryptography.X509Certificates.X509Certificate2?

Is there a plan to support these two Extensions in High Level API?

Author: amin1best
Assignees: -
Labels:

area-System.Security, untriaged

Milestone: -

@krwq
Copy link
Member

krwq commented Sep 20, 2021

@amin1best I do not believe have any easy way as of now at least (at least not other than X509Extension.Format(true)).

It is possible to do but in slightly more complicated way:

  • you iterate all extensions (X509Certificate2.Extensions), you find the one with the right OID by checking: X509Extension.Oid?.Value, i.e. for AIA that will be "1.3.6.1.5.5.7.1.1" then you parse RawData with the AsnReader

i.e. for searching AIA the code will look like following (copy paste of some pieces of my old code which is based on the code found somewhere in the framework), you will need to adjust for whatever you need:

        const string AuthorityInformationAccess = "1.3.6.1.5.5.7.1.1";
        const string CertificateAuthorityIssuers = "1.3.6.1.5.5.7.48.2";

// when you enumarate all extensions, you can do i.e.:
//                if (ext.Oid?.Value == AuthorityInformationAccess)
//                {
//                    string? uri = FindHttpAiaRecord(ext.RawData, CertificateAuthorityIssuers);
//                    Console.WriteLine($"Issuer uri read from extension: {(uri ?? "<error>")}");
//                }
        private static string? FindHttpAiaRecord(ReadOnlyMemory<byte> authorityInformationAccess, string recordTypeOid)
        {
            try
            {
                AsnReader reader = new AsnReader(authorityInformationAccess, AsnEncodingRules.DER);
                AsnReader sequenceReader = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                Asn1Tag generalNameTag = new Asn1Tag(TagClass.ContextSpecific, 6);

                while (sequenceReader.HasData)
                {
                    AsnReader accessDescriptionSequenceReader = sequenceReader.ReadSequence();
                    string oid = accessDescriptionSequenceReader.ReadObjectIdentifier();
                    Asn1Tag tag = accessDescriptionSequenceReader.PeekTag();
                    if (oid == recordTypeOid && tag.HasSameClassAndValue(generalNameTag))
                    {
                        string generalName = accessDescriptionSequenceReader.ReadCharacterString(UniversalTagNumber.IA5String, generalNameTag);
                        return generalName;
                    }
                }
            }
            catch (CryptographicException)
            {
                // Treat any ASN errors as if the extension was missing.
            }
            catch (AsnContentException)
            {
                // Treat any ASN errors as if the extension was missing.
            }

            return null;
        }

        internal static string ReadAnyAsnString(AsnReader tavReader)
        {
            Asn1Tag tag = tavReader.PeekTag();

            if (tag.TagClass != TagClass.Universal)
            {
                throw new CryptographicException("Invalid encoding");
            }

            switch ((UniversalTagNumber)tag.TagValue)
            {
                case UniversalTagNumber.BMPString:
                case UniversalTagNumber.IA5String:
                case UniversalTagNumber.NumericString:
                case UniversalTagNumber.PrintableString:
                case UniversalTagNumber.UTF8String:
                case UniversalTagNumber.T61String:
                    // .NET's string comparisons start by checking the length, so a trailing
                    // NULL character which was literally embedded in the DER would cause a
                    // failure in .NET whereas it wouldn't have with strcmp.
                    return tavReader.ReadCharacterString((UniversalTagNumber)tag.TagValue).TrimEnd('\0');

                default:
                    throw new CryptographicException("Invalid encoding");
            }
        }

most likely the code will be either very similar (hopefully difference just in OID passed in to the method but you will need to refer to the spec.

Hope that helps

@bartonjs
Copy link
Member

Is there a plan to support these two Extensions in High Level API?

Not a 100% concrete plan, but they're part of the list of prerequisites in #29547 (comment), ideally they are being done in .NET 7 (similar to all of the other extensions you asked about in 59191).

How can I set these fields in System.Security.Cryptography.X509Certificates.X509Certificate2?

You can't, X509Certificate2 represents a complete (signed) certificate, it's immutable. You can build certificates with them using CertificateRequest, but you currently have to do the work to encode the extensions.

How can get these fields and access methods in System.Security.Cryptography.X509Certificates.X509Certificate2?

Currently, you'd need to walk the extensions, find the one you want, and decode it with AsnReader. But what's your scenario (why do you want the values)? In the 20 years of .NET you're either the first, or one of the very few, to want this information 😄.

@bartonjs bartonjs added question Answer questions and provide assistance, not an issue with source code or documentation. and removed untriaged New issue has not been triaged by the area owner labels Sep 20, 2021
@bartonjs bartonjs added this to the Future milestone Sep 20, 2021
@amin1best
Copy link
Author

    internal static string ReadAnyAsnString(AsnReader tavReader)
    {
        Asn1Tag tag = tavReader.PeekTag();

        if (tag.TagClass != TagClass.Universal)
        {
            throw new CryptographicException("Invalid encoding");
        }

        switch ((UniversalTagNumber)tag.TagValue)
        {
            case UniversalTagNumber.BMPString:
            case UniversalTagNumber.IA5String:
            case UniversalTagNumber.NumericString:
            case UniversalTagNumber.PrintableString:
            case UniversalTagNumber.UTF8String:
            case UniversalTagNumber.T61String:
                // .NET's string comparisons start by checking the length, so a trailing
                // NULL character which was literally embedded in the DER would cause a
                // failure in .NET whereas it wouldn't have with strcmp.
                return tavReader.ReadCharacterString((UniversalTagNumber)tag.TagValue).TrimEnd('\0');

            default:
                throw new CryptographicException("Invalid encoding");
        }
    }

Thanks @krwq for reply with sample code.
Can I ask you to explain more about ReadAnyAsnString function?

@amin1best
Copy link
Author

Not a 100% concrete plan, but they're part of the list of prerequisites in #29547 (comment), ideally they are being done in .NET 7 (similar to all of the other extensions you asked about in 59191).

Thanks for adding these extensions to .Net 7 Milestone. It would be great if you could support all extensions in rfc5280.

You can't, X509Certificate2 represents a complete (signed) certificate, it's immutable. You can build certificates with them using CertificateRequest, but you currently have to do the work to encode the extensions.

Sorry, I was wrong, I meant CertificateRequest.

Currently, you'd need to walk the extensions, find the one you want, and decode it with AsnReader. But what's your scenario (why do you want the values)? In the 20 years of .NET you're either the first, or one of the very few, to want this information 😄.

😅
In my work, certificates from many different sources have been used for different applications. I want to have a dashboard that displays all different certificates along with their information and status.

I am a beginner in ASN.1. Thanks for your answers @bartonjs

@krwq
Copy link
Member

krwq commented Sep 21, 2021

Can I ask you to explain more about ReadAnyAsnString function?

I guess I copied too much code from one of my projects

@bartonjs
Copy link
Member

bartonjs commented Mar 5, 2022

Since all questions seem to be answered, and there hasn't been activity for a while, closing.

@bartonjs bartonjs closed this as completed Mar 5, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Security question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

3 participants