Skip to content

X509AuthorityKeyIdentifierExtension should be public #24931

@heri16

Description

@heri16

API Proposal

namespace System.Security.Cryptography.X509Certificates
{
    public sealed partial class X509AuthorityKeyIdentifierExtension : X509Extension
    {
        public X509AuthorityKeyIdentifierExtension() { }
        public X509AuthorityKeyIdentifierExtension(byte[] rawData, bool critical = false) { }
        public X509AuthorityKeyIdentifierExtension(System.ReadOnlySpan<byte> rawData, bool critical = false) { }

        // KeyIdentifier is optional in the extension, and could be empty, so Nullable is
        // important to distinguish "not present" from "present and empty"
        public System.ReadOnlyMemory<byte>? KeyIdentifier { get; }

        // A well-formed use of this extension has Issuer and SerialNumber both set, or neither set.
        // The 99.99% use of Issuer is to convey one (and only one) X500DistinguishedName,
        // when that is true then the value is in SimpleIssuer.
        public System.ReadOnlyMemory<byte>? RawIssuer { get; }
        public System.Security.Cryptography.X509Certificates.X500DistinguishedName? SimpleIssuer { get; }
        public System.ReadOnlyMemory<byte>? SerialNumber { get; }

        // The guidance to public/Internet CAs is to only create this extension with a KeyIdentifier value,
        // but Enterprise and Private PKI can do whatever they want.
        // The Create routines map to the three possibilities from IETF RFC 5280:
        // * KeyIdentifier-only
        // * IssuerName + SerialNumber (no KeyIdentifier)
        // * All three values.
        //
        // Naming: The keyIdentifier value here has to match the Subject Key Identifier value
        // from the issuing Certificate Authority, so I added "Subject" to the method and
        // parameter names here, but we could remove them.
        public static X509AuthorityKeyIdentifierExtension CreateFromSubjectKeyIdentifier(
            byte[] subjectKeyIdentifier);
        public static X509AuthorityKeyIdentifierExtension CreateFromSubjectKeyIdentifier(
            ReadOnlySpan<byte> subjectKeyIdentifier);
        public static X509AuthorityKeyIdentifierExtension CreateFromSubjectKeyIdentifier(
            X509SubjectKeyIdentifierExtension subjectKeyIdentifier);

        public static X509AuthorityKeyIdentifierExtension CreateFromIssuerNameAndSerialNumber(
            X500DistinguishedName issuerName, byte[] serialNumber);
        public static X509AuthorityKeyIdentifierExtension CreateFromIssuerNameAndSerialNumber(
            X500DistinguishedName issuerName, ReadOnlySpan<byte> serialNumber);

        public static X509AuthorityKeyIdentifierExtension Create(
            byte[] keyIdentifier, X500DistinguishedName issuerName, byte[] serialNumber);
        public static X509AuthorityKeyIdentifierExtension Create(
            ReadOnlySpan<byte> keyIdentifier, X500DistinguishedName issuerName, ReadOnlySpan<byte> serialNumber);

        // This method was added as convenience, but may be more trouble than it's worth.
        // throws if includeKeyIdentifier is true but the certificate has no Subject Key Identifier
        // extension, and "for best results" includeKeyIdentifier != includeIssuerAndSerial,
        // so maybe the right answer is to make callers find the presence/absence of the SKI
        // themselves and call an appropriate alternative.
        public static X509AuthorityKeyIdentifierExtension CreateFromCertificate(
            X509Certificate2 certificate, bool includeKeyIdentifier, bool includeIssuerAndSerial);
    }

    // After here are allocation-reducing enhancements used in the implementation.

    public partial class X509Certificate
    {
        public System.ReadOnlyMemory<byte> SerialNumberBytes { get; }

        // Existing members that can't be used easily:

        // Signed, big-endian, hex, allocates per call
        // public string [X509Certificate2::]SerialNumberString { get; }
        // public string GetSerialNumberString();

        // Signed, LITTLE-endian, allocates per call
        // public byte[] GetSerialNumber();
    }

    public partial class X509SubjectKeyIdentifierExtension
    {
        // Throws CryptographicException on unpopulated object
        public System.ReadOnlyMemory<byte> SubjectKeyIdentifierBytes { get; }

        // Existing members that can't be used easily:

        // hex string, so it forces buffer management and CPU to decode it back to bytes
        // public string? SubjectKeyIdentifier { get; }
        
    }
}

Original

X509AuthorityKeyIdentifierExtension is currently a sealed class. Should make it public unless there is a good reason in keeping it sealed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-System.SecurityblockingMarks issues that we want to fast track in order to unblock other important work

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions