dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.91k stars 4.63k forks source link

[API Proposal]: Make System.Security.Cryptography.Oids constants public #87270

Open ThreeSevenths opened 1 year ago

ThreeSevenths commented 1 year ago

Background and motivation

As a C# developer, I would like to have the Oids constants exposed to me so that I do not need to add my own constants for the same thing, thus reducing the size of my final output (every byte counts 😎) and reducing the chance of error.

The runtime already includes many constants as an internal class, dotnet/runtime - Oids.cs which could easily be made public instead of internal.

API Proposal

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Security.Cryptography
{
    public static partial class Oids
    {
        // Symmetric encryption algorithms
        public const string Rc2Cbc = "1.2.840.113549.3.2";
        public const string Rc4 = "1.2.840.113549.3.4";
        public const string TripleDesCbc = "1.2.840.113549.3.7";
        public const string DesCbc = "1.3.14.3.2.7";
        public const string Aes128Cbc = "2.16.840.1.101.3.4.1.2";
        public const string Aes192Cbc = "2.16.840.1.101.3.4.1.22";
        public const string Aes256Cbc = "2.16.840.1.101.3.4.1.42";

        // Asymmetric encryption algorithms
        public const string Dsa = "1.2.840.10040.4.1";
        public const string Rsa = "1.2.840.113549.1.1.1";
        public const string RsaOaep = "1.2.840.113549.1.1.7";
        public const string RsaPss = "1.2.840.113549.1.1.10";
        public const string RsaPkcs1Md5 = "1.2.840.113549.1.1.4";
        public const string RsaPkcs1Sha1 = "1.2.840.113549.1.1.5";
        public const string RsaPkcs1Sha256 = "1.2.840.113549.1.1.11";
        public const string RsaPkcs1Sha384 = "1.2.840.113549.1.1.12";
        public const string RsaPkcs1Sha512 = "1.2.840.113549.1.1.13";
        public const string RsaPkcs1Sha3_256 = "2.16.840.1.101.3.4.3.14";
        public const string RsaPkcs1Sha3_384 = "2.16.840.1.101.3.4.3.15";
        public const string RsaPkcs1Sha3_512 = "2.16.840.1.101.3.4.3.16";
        public const string Esdh = "1.2.840.113549.1.9.16.3.5";
        public const string EcDiffieHellman = "1.3.132.1.12";
        public const string DiffieHellman = "1.2.840.10046.2.1";
        public const string DiffieHellmanPkcs3 = "1.2.840.113549.1.3.1";

        // Cryptographic Attribute Types
        public const string SigningTime = "1.2.840.113549.1.9.5";
        public const string ContentType = "1.2.840.113549.1.9.3";
        public const string DocumentDescription = "1.3.6.1.4.1.311.88.2.2";
        public const string MessageDigest = "1.2.840.113549.1.9.4";
        public const string CounterSigner = "1.2.840.113549.1.9.6";
        public const string SigningCertificate = "1.2.840.113549.1.9.16.2.12";
        public const string SigningCertificateV2 = "1.2.840.113549.1.9.16.2.47";
        public const string DocumentName = "1.3.6.1.4.1.311.88.2.1";
        public const string LocalKeyId = "1.2.840.113549.1.9.21";
        public const string EnrollCertTypeExtension = "1.3.6.1.4.1.311.20.2";
        public const string UserPrincipalName = "1.3.6.1.4.1.311.20.2.3";
        public const string CertificateTemplate = "1.3.6.1.4.1.311.21.7";
        public const string ApplicationCertPolicies = "1.3.6.1.4.1.311.21.10";
        public const string AuthorityInformationAccess = "1.3.6.1.5.5.7.1.1";
        public const string OcspEndpoint = "1.3.6.1.5.5.7.48.1";
        public const string CertificateAuthorityIssuers = "1.3.6.1.5.5.7.48.2";
        public const string Pkcs9ExtensionRequest = "1.2.840.113549.1.9.14";

        // Key wrap algorithms
        public const string CmsRc2Wrap = "1.2.840.113549.1.9.16.3.7";
        public const string Cms3DesWrap = "1.2.840.113549.1.9.16.3.6";

        // PKCS7 Content Types.
        public const string Pkcs7Data = "1.2.840.113549.1.7.1";
        public const string Pkcs7Signed = "1.2.840.113549.1.7.2";
        public const string Pkcs7Enveloped = "1.2.840.113549.1.7.3";
        public const string Pkcs7SignedEnveloped = "1.2.840.113549.1.7.4";
        public const string Pkcs7Hashed = "1.2.840.113549.1.7.5";
        public const string Pkcs7Encrypted = "1.2.840.113549.1.7.6";

        public const string Md5 = "1.2.840.113549.2.5";
        public const string Sha1 = "1.3.14.3.2.26";
        public const string Sha256 = "2.16.840.1.101.3.4.2.1";
        public const string Sha384 = "2.16.840.1.101.3.4.2.2";
        public const string Sha512 = "2.16.840.1.101.3.4.2.3";
        public const string Sha3_256 = "2.16.840.1.101.3.4.2.8";
        public const string Sha3_384 = "2.16.840.1.101.3.4.2.9";
        public const string Sha3_512 = "2.16.840.1.101.3.4.2.10";

        // DSA CMS uses the combined signature+digest OID
        public const string DsaWithSha1 = "1.2.840.10040.4.3";
        public const string DsaWithSha256 = "2.16.840.1.101.3.4.3.2";
        public const string DsaWithSha384 = "2.16.840.1.101.3.4.3.3";
        public const string DsaWithSha512 = "2.16.840.1.101.3.4.3.4";

        // ECDSA CMS uses the combined signature+digest OID
        // https://tools.ietf.org/html/rfc5753#section-2.1.1
        public const string EcPrimeField = "1.2.840.10045.1.1";
        public const string EcChar2Field = "1.2.840.10045.1.2";
        public const string EcChar2TrinomialBasis = "1.2.840.10045.1.2.3.2";
        public const string EcChar2PentanomialBasis = "1.2.840.10045.1.2.3.3";
        public const string EcPublicKey = "1.2.840.10045.2.1";
        public const string ECDsaWithSha1 = "1.2.840.10045.4.1";
        public const string ECDsaWithSha256 = "1.2.840.10045.4.3.2";
        public const string ECDsaWithSha384 = "1.2.840.10045.4.3.3";
        public const string ECDsaWithSha512 = "1.2.840.10045.4.3.4";

        public const string ECDsaWithSha3_256 = "2.16.840.1.101.3.4.3.10";
        public const string ECDsaWithSha3_384 = "2.16.840.1.101.3.4.3.11";
        public const string ECDsaWithSha3_512 = "2.16.840.1.101.3.4.3.12";

        public const string Mgf1 = "1.2.840.113549.1.1.8";
        public const string PSpecified = "1.2.840.113549.1.1.9";

        // PKCS#7
        public const string NoSignature = "1.3.6.1.5.5.7.6.2";

        // X500 Names
        public const string CommonName = "2.5.4.3";
        public const string CountryOrRegionName = "2.5.4.6";
        public const string LocalityName = "2.5.4.7";
        public const string StateOrProvinceName = "2.5.4.8";
        public const string Organization = "2.5.4.10";
        public const string OrganizationalUnit = "2.5.4.11";
        public const string EmailAddress = "1.2.840.113549.1.9.1";

        // Cert Extensions
        public const string BasicConstraints = "2.5.29.10";
        public const string SubjectKeyIdentifier = "2.5.29.14";
        public const string KeyUsage = "2.5.29.15";
        public const string SubjectAltName = "2.5.29.17";
        public const string IssuerAltName = "2.5.29.18";
        public const string BasicConstraints2 = "2.5.29.19";
        public const string CrlNumber = "2.5.29.20";
        public const string CrlReasons = "2.5.29.21";
        public const string CrlDistributionPoints = "2.5.29.31";
        public const string CertPolicies = "2.5.29.32";
        public const string AnyCertPolicy = "2.5.29.32.0";
        public const string CertPolicyMappings = "2.5.29.33";
        public const string AuthorityKeyIdentifier = "2.5.29.35";
        public const string CertPolicyConstraints = "2.5.29.36";
        public const string EnhancedKeyUsage = "2.5.29.37";
        public const string InhibitAnyPolicyExtension = "2.5.29.54";

        // RFC3161 Timestamping
        public const string TstInfo = "1.2.840.113549.1.9.16.1.4";
        public const string TimeStampingPurpose = "1.3.6.1.5.5.7.3.8";

        // PKCS#12
        private const string Pkcs12Prefix = "1.2.840.113549.1.12.";
        private const string Pkcs12PbePrefix = Pkcs12Prefix + "1.";
        public const string Pkcs12PbeWithShaAnd3Key3Des = Pkcs12PbePrefix + "3";
        public const string Pkcs12PbeWithShaAnd2Key3Des = Pkcs12PbePrefix + "4";
        public const string Pkcs12PbeWithShaAnd128BitRC2 = Pkcs12PbePrefix + "5";
        public const string Pkcs12PbeWithShaAnd40BitRC2 = Pkcs12PbePrefix + "6";
        private const string Pkcs12BagTypesPrefix = Pkcs12Prefix + "10.1.";
        public const string Pkcs12KeyBag = Pkcs12BagTypesPrefix + "1";
        public const string Pkcs12ShroudedKeyBag = Pkcs12BagTypesPrefix + "2";
        public const string Pkcs12CertBag = Pkcs12BagTypesPrefix + "3";
        public const string Pkcs12CrlBag = Pkcs12BagTypesPrefix + "4";
        public const string Pkcs12SecretBag = Pkcs12BagTypesPrefix + "5";
        public const string Pkcs12SafeContentsBag = Pkcs12BagTypesPrefix + "6";
        public const string Pkcs12X509CertBagType = "1.2.840.113549.1.9.22.1";
        public const string Pkcs12SdsiCertBagType = "1.2.840.113549.1.9.22.2";

        // PKCS#5
        private const string Pkcs5Prefix = "1.2.840.113549.1.5.";
        public const string PbeWithMD5AndDESCBC = Pkcs5Prefix + "3";
        public const string PbeWithMD5AndRC2CBC = Pkcs5Prefix + "6";
        public const string PbeWithSha1AndDESCBC = Pkcs5Prefix + "10";
        public const string PbeWithSha1AndRC2CBC = Pkcs5Prefix + "11";
        public const string Pbkdf2 = Pkcs5Prefix + "12";
        public const string PasswordBasedEncryptionScheme2 = Pkcs5Prefix + "13";

        private const string RsaDsiDigestAlgorithmPrefix = "1.2.840.113549.2.";
        public const string HmacWithSha1 = RsaDsiDigestAlgorithmPrefix + "7";
        public const string HmacWithSha256 = RsaDsiDigestAlgorithmPrefix + "9";
        public const string HmacWithSha384 = RsaDsiDigestAlgorithmPrefix + "10";
        public const string HmacWithSha512 = RsaDsiDigestAlgorithmPrefix + "11";

        // Elliptic Curve curve identifiers
        public const string secp256r1 = "1.2.840.10045.3.1.7";
        public const string secp384r1 = "1.3.132.0.34";
        public const string secp521r1 = "1.3.132.0.35";

        // LDAP
        public const string DomainComponent = "0.9.2342.19200300.100.1.25";
    }
}

API Usage

// Fancy the value
var c = new MyFancyCollection<int>();
c.Fancy(42);

// Getting the values out
foreach (var v in c)
    Console.WriteLine(v);

Alternative Designs

An alternative design could include additional documentation, a big huge warning about their usage, or a tree hierarchy that maps the oids in oid hierarchy space.

Risks

There are no risks of any backward compatibility issues. There is a slight business risk that some developers that ought not to do their own certificate processing will be empowered to do so with these constants available to them.

ghost commented 1 year ago

Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones See info in area-owners.md if you want to be subscribed.

Issue Details
### Background and motivation As a C# developer, I would like to have the Oids constants exposed to me so that I do not need to add my own constants for the same thing, thus reducing the size of my final output (every byte counts 😎) and reducing the chance of error. The runtime already includes many constants as an internal class, [dotnet/runtime - Oids.cs](https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Security/Cryptography/Oids.cs) which could easily be made public instead of internal. ### API Proposal ```csharp // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Security.Cryptography { public static partial class Oids { // Symmetric encryption algorithms public const string Rc2Cbc = "1.2.840.113549.3.2"; public const string Rc4 = "1.2.840.113549.3.4"; public const string TripleDesCbc = "1.2.840.113549.3.7"; public const string DesCbc = "1.3.14.3.2.7"; public const string Aes128Cbc = "2.16.840.1.101.3.4.1.2"; public const string Aes192Cbc = "2.16.840.1.101.3.4.1.22"; public const string Aes256Cbc = "2.16.840.1.101.3.4.1.42"; // Asymmetric encryption algorithms public const string Dsa = "1.2.840.10040.4.1"; public const string Rsa = "1.2.840.113549.1.1.1"; public const string RsaOaep = "1.2.840.113549.1.1.7"; public const string RsaPss = "1.2.840.113549.1.1.10"; public const string RsaPkcs1Md5 = "1.2.840.113549.1.1.4"; public const string RsaPkcs1Sha1 = "1.2.840.113549.1.1.5"; public const string RsaPkcs1Sha256 = "1.2.840.113549.1.1.11"; public const string RsaPkcs1Sha384 = "1.2.840.113549.1.1.12"; public const string RsaPkcs1Sha512 = "1.2.840.113549.1.1.13"; public const string RsaPkcs1Sha3_256 = "2.16.840.1.101.3.4.3.14"; public const string RsaPkcs1Sha3_384 = "2.16.840.1.101.3.4.3.15"; public const string RsaPkcs1Sha3_512 = "2.16.840.1.101.3.4.3.16"; public const string Esdh = "1.2.840.113549.1.9.16.3.5"; public const string EcDiffieHellman = "1.3.132.1.12"; public const string DiffieHellman = "1.2.840.10046.2.1"; public const string DiffieHellmanPkcs3 = "1.2.840.113549.1.3.1"; // Cryptographic Attribute Types public const string SigningTime = "1.2.840.113549.1.9.5"; public const string ContentType = "1.2.840.113549.1.9.3"; public const string DocumentDescription = "1.3.6.1.4.1.311.88.2.2"; public const string MessageDigest = "1.2.840.113549.1.9.4"; public const string CounterSigner = "1.2.840.113549.1.9.6"; public const string SigningCertificate = "1.2.840.113549.1.9.16.2.12"; public const string SigningCertificateV2 = "1.2.840.113549.1.9.16.2.47"; public const string DocumentName = "1.3.6.1.4.1.311.88.2.1"; public const string LocalKeyId = "1.2.840.113549.1.9.21"; public const string EnrollCertTypeExtension = "1.3.6.1.4.1.311.20.2"; public const string UserPrincipalName = "1.3.6.1.4.1.311.20.2.3"; public const string CertificateTemplate = "1.3.6.1.4.1.311.21.7"; public const string ApplicationCertPolicies = "1.3.6.1.4.1.311.21.10"; public const string AuthorityInformationAccess = "1.3.6.1.5.5.7.1.1"; public const string OcspEndpoint = "1.3.6.1.5.5.7.48.1"; public const string CertificateAuthorityIssuers = "1.3.6.1.5.5.7.48.2"; public const string Pkcs9ExtensionRequest = "1.2.840.113549.1.9.14"; // Key wrap algorithms public const string CmsRc2Wrap = "1.2.840.113549.1.9.16.3.7"; public const string Cms3DesWrap = "1.2.840.113549.1.9.16.3.6"; // PKCS7 Content Types. public const string Pkcs7Data = "1.2.840.113549.1.7.1"; public const string Pkcs7Signed = "1.2.840.113549.1.7.2"; public const string Pkcs7Enveloped = "1.2.840.113549.1.7.3"; public const string Pkcs7SignedEnveloped = "1.2.840.113549.1.7.4"; public const string Pkcs7Hashed = "1.2.840.113549.1.7.5"; public const string Pkcs7Encrypted = "1.2.840.113549.1.7.6"; public const string Md5 = "1.2.840.113549.2.5"; public const string Sha1 = "1.3.14.3.2.26"; public const string Sha256 = "2.16.840.1.101.3.4.2.1"; public const string Sha384 = "2.16.840.1.101.3.4.2.2"; public const string Sha512 = "2.16.840.1.101.3.4.2.3"; public const string Sha3_256 = "2.16.840.1.101.3.4.2.8"; public const string Sha3_384 = "2.16.840.1.101.3.4.2.9"; public const string Sha3_512 = "2.16.840.1.101.3.4.2.10"; // DSA CMS uses the combined signature+digest OID public const string DsaWithSha1 = "1.2.840.10040.4.3"; public const string DsaWithSha256 = "2.16.840.1.101.3.4.3.2"; public const string DsaWithSha384 = "2.16.840.1.101.3.4.3.3"; public const string DsaWithSha512 = "2.16.840.1.101.3.4.3.4"; // ECDSA CMS uses the combined signature+digest OID // https://tools.ietf.org/html/rfc5753#section-2.1.1 public const string EcPrimeField = "1.2.840.10045.1.1"; public const string EcChar2Field = "1.2.840.10045.1.2"; public const string EcChar2TrinomialBasis = "1.2.840.10045.1.2.3.2"; public const string EcChar2PentanomialBasis = "1.2.840.10045.1.2.3.3"; public const string EcPublicKey = "1.2.840.10045.2.1"; public const string ECDsaWithSha1 = "1.2.840.10045.4.1"; public const string ECDsaWithSha256 = "1.2.840.10045.4.3.2"; public const string ECDsaWithSha384 = "1.2.840.10045.4.3.3"; public const string ECDsaWithSha512 = "1.2.840.10045.4.3.4"; public const string ECDsaWithSha3_256 = "2.16.840.1.101.3.4.3.10"; public const string ECDsaWithSha3_384 = "2.16.840.1.101.3.4.3.11"; public const string ECDsaWithSha3_512 = "2.16.840.1.101.3.4.3.12"; public const string Mgf1 = "1.2.840.113549.1.1.8"; public const string PSpecified = "1.2.840.113549.1.1.9"; // PKCS#7 public const string NoSignature = "1.3.6.1.5.5.7.6.2"; // X500 Names public const string CommonName = "2.5.4.3"; public const string CountryOrRegionName = "2.5.4.6"; public const string LocalityName = "2.5.4.7"; public const string StateOrProvinceName = "2.5.4.8"; public const string Organization = "2.5.4.10"; public const string OrganizationalUnit = "2.5.4.11"; public const string EmailAddress = "1.2.840.113549.1.9.1"; // Cert Extensions public const string BasicConstraints = "2.5.29.10"; public const string SubjectKeyIdentifier = "2.5.29.14"; public const string KeyUsage = "2.5.29.15"; public const string SubjectAltName = "2.5.29.17"; public const string IssuerAltName = "2.5.29.18"; public const string BasicConstraints2 = "2.5.29.19"; public const string CrlNumber = "2.5.29.20"; public const string CrlReasons = "2.5.29.21"; public const string CrlDistributionPoints = "2.5.29.31"; public const string CertPolicies = "2.5.29.32"; public const string AnyCertPolicy = "2.5.29.32.0"; public const string CertPolicyMappings = "2.5.29.33"; public const string AuthorityKeyIdentifier = "2.5.29.35"; public const string CertPolicyConstraints = "2.5.29.36"; public const string EnhancedKeyUsage = "2.5.29.37"; public const string InhibitAnyPolicyExtension = "2.5.29.54"; // RFC3161 Timestamping public const string TstInfo = "1.2.840.113549.1.9.16.1.4"; public const string TimeStampingPurpose = "1.3.6.1.5.5.7.3.8"; // PKCS#12 private const string Pkcs12Prefix = "1.2.840.113549.1.12."; private const string Pkcs12PbePrefix = Pkcs12Prefix + "1."; public const string Pkcs12PbeWithShaAnd3Key3Des = Pkcs12PbePrefix + "3"; public const string Pkcs12PbeWithShaAnd2Key3Des = Pkcs12PbePrefix + "4"; public const string Pkcs12PbeWithShaAnd128BitRC2 = Pkcs12PbePrefix + "5"; public const string Pkcs12PbeWithShaAnd40BitRC2 = Pkcs12PbePrefix + "6"; private const string Pkcs12BagTypesPrefix = Pkcs12Prefix + "10.1."; public const string Pkcs12KeyBag = Pkcs12BagTypesPrefix + "1"; public const string Pkcs12ShroudedKeyBag = Pkcs12BagTypesPrefix + "2"; public const string Pkcs12CertBag = Pkcs12BagTypesPrefix + "3"; public const string Pkcs12CrlBag = Pkcs12BagTypesPrefix + "4"; public const string Pkcs12SecretBag = Pkcs12BagTypesPrefix + "5"; public const string Pkcs12SafeContentsBag = Pkcs12BagTypesPrefix + "6"; public const string Pkcs12X509CertBagType = "1.2.840.113549.1.9.22.1"; public const string Pkcs12SdsiCertBagType = "1.2.840.113549.1.9.22.2"; // PKCS#5 private const string Pkcs5Prefix = "1.2.840.113549.1.5."; public const string PbeWithMD5AndDESCBC = Pkcs5Prefix + "3"; public const string PbeWithMD5AndRC2CBC = Pkcs5Prefix + "6"; public const string PbeWithSha1AndDESCBC = Pkcs5Prefix + "10"; public const string PbeWithSha1AndRC2CBC = Pkcs5Prefix + "11"; public const string Pbkdf2 = Pkcs5Prefix + "12"; public const string PasswordBasedEncryptionScheme2 = Pkcs5Prefix + "13"; private const string RsaDsiDigestAlgorithmPrefix = "1.2.840.113549.2."; public const string HmacWithSha1 = RsaDsiDigestAlgorithmPrefix + "7"; public const string HmacWithSha256 = RsaDsiDigestAlgorithmPrefix + "9"; public const string HmacWithSha384 = RsaDsiDigestAlgorithmPrefix + "10"; public const string HmacWithSha512 = RsaDsiDigestAlgorithmPrefix + "11"; // Elliptic Curve curve identifiers public const string secp256r1 = "1.2.840.10045.3.1.7"; public const string secp384r1 = "1.3.132.0.34"; public const string secp521r1 = "1.3.132.0.35"; // LDAP public const string DomainComponent = "0.9.2342.19200300.100.1.25"; } } ``` ### API Usage ```csharp // Fancy the value var c = new MyFancyCollection(); c.Fancy(42); // Getting the values out foreach (var v in c) Console.WriteLine(v); ``` ### Alternative Designs An alternative design could include additional documentation, a big huge warning about their usage, or a tree hierarchy that maps the oids in oid hierarchy space. ### Risks There are no risks of any backward compatibility issues. There is a slight business risk that some developers that ought not to do their own certificate processing will be empowered to do so with these constants available to them.
Author: ThreeSevenths
Assignees: -
Labels: `api-suggestion`, `area-System.Security`
Milestone: -
vcsjones commented 1 year ago

I've been thinking about this for a while and glad someone else proposed it 😄.

My immediate thoughts are:

  1. Do we want to expose strings, or Oid instances? I like the strings because they are cheaper than an Oid instance.

  2. We need to figure out better names for these and how to organize them. We could do nested static classes:

    public static class Oids {
        public static class HashAlgs {
            public const string SHA3_256 = "2.16.840.1.101.3.4.2.8";
        }
    }

    but that might be arbitrary. Going full Registry like IsoUtu.Country.Us.Orgaization.Gov.Csor.HashAlgs.SHA3_256 would be silly, I think.

ThreeSevenths commented 1 year ago
  1. Do we want to expose strings, or Oid instances? I like the strings because they are cheaper than an Oid instance.

I'd agree strings are the way to go. Oid isn't heavy, but it's definitely not as light as a string. Calling .Value or adding an equality comparer could work as well. It's also less work since they are strings today. In my usage I'm doing oidinstance.Value anyway since I don't want to allocate a readonly Oid for a simple comparison.

  1. We need to figure out better names for these and how to organize them. We could do nested static classes:

I don't mind a logical hierarchy like your example. HashAlgorithms, EnhancedKeyUsages, Extensions, etc. Some permutation of a component of the friendly name might be the most useful. I agree following the 'rich' hierarchy of actual oids would be silly and difficult to navigate.

Ultimately I initially was thinking what's easy to do, and Find internal > Replace public is almost no effort however there is some opportunity here to make it easier to use. I think you still need to know what you're doing to use these constants directly, and there is lots of public API today to make this work in many situations for the vast majority of use cases.

bartonjs commented 1 year ago

Find internal > Replace public is almost no effort however there is some opportunity here to make it easier to use

While that may be a reasonable starting point, each and every name would have to be examined for appropriateness. Esdh doesn't seem like one we'd want to leave collapsed like that. Rsa should arguably be RsaEncryption, and maybe we want to say that in these consts RSA should be capital since it's capital elsewhere in our API surface, etc.

We need to figure out better names for these and how to organize them. We could do nested static classes:

Two problems with this (though it might end up being the best answer anyways): 1) it's definitely arbitrary... id-rsaEncryption is one of the trickier ones to place... it can be a signature algorithm or an encryption algorithm, since it's just a generic "RSA will be used here, some other detail will provide better context". 2) nested types don't work equally well in all languages, so someone should see what the experience would be in C#, F#, VB.NET, and ideally even COBOL.NET. Yeah, we used nested types for well-known EC curves, but we also felt that the number of people using them would be small. While OID-users are still somewhat small, they're a bigger small than EC-curve specifiers/verifiers, so cross-language usability matters more.

Do we want to expose strings, or Oid instances?

Yep. The answer might be both... Foo and FooOid, maybe. The string form is nicer to switch over, and can avoid allocating unnecessarily. The Oid form has the advantage that everyone can share the same reference, reducing long-term allocations. That's why we end up with both in our well-known OIDs tables. Verifiers typically want the string, creators typically want the shared Oid reference.

Another way for doing both would be to put strings as (e.g.) public const string System.Formats.Asn1.OidValues.Pkcs12CertBag = "..."; and Oids as (e.g.) public Oid System.Security.Cryptography.WellKnownOids.Pkcs12CertBag { get; } => s_pkcs12CertBag ??= InitializeOid(System.Formats.Asn1.OidValues.Pkcs12CertBag);

vvHedgehog commented 1 year ago

It will be great that WellKnown Oids became public.

vcsjones commented 1 year ago

I looked around a bit at other ecosystems to see if, or how, anyone else did this.

Java and Ruby use strings for OIDs. Go uses a typealias as []int. So no good examples there.

Rust does. Rust has a very lean stdlib. All of their cryptography is in a separate crate, including OIDs. The RustCrypto project is as close as you could get to something in-box though.

They generate a list of... every... OID.

https://github.com/RustCrypto/formats/blob/master/const-oid/src/db/gen.rs

"all of them" is probably too much for most people's needs. I was more interested in how they are organized. They are all in separate modules by the RFC or document that that defines them. Loosely, Rust modules could be static classes or namespaces.

In .NET it would be something like:

namespace System.Security.Cryptography.Oids;

public static class Fips202 {
    public static Oid SHA3_256 => MakeOid("2.16.840.1.101.3.4.2.8");
    // etc
}

public static class Rfc4519 {
    public static Oid CommonName => MakeOid("2.5.4.3");
}

There is a certain amount of this that I like, but some things going against it:

  1. Most people probably don't know what RFC or document define some of the OIDs they are looking for. Would you expect CommonName in Rfc4519, or some class called X520?
  2. Rust has some luxury in being that it's a separate crate. Particularly they can add as many as they want and not worry about crate size or app size since Rust apps are statically linked and trimmed by default.

So I don't feel that rust gets us any close to a particular answer, but it does make me think a bit more strongly that any attempt to organize them is going to feel arbitrary.

I don't feel that I am particularly closer to having a better understanding of the direction .NET should take, and there isn't a ton of prior art to look at.

I think a point worth asking though, what OIDs do people feel that they are using frequently enough that would necessitate an accelerator?

ThreeSevenths commented 1 year ago

I think it's sufficient to start with EKUs, algos that are in common usage in .NET, and x509 related [for my use case 😀]. Ideally, I'd say you should be able to read an ASN1 stream for a bog standard cert from signtool and match the OIDs that would be present. Most of the current OIDs seem to work toward that purpose.

  1. Most people probably don't know what RFC or document define some of the OIDs they are looking for. Would you expect CommonName in Rfc4519, or some class called X520?

I've always thought a key feature for .NET and friends is our excellent tooling, IntelliSense in this case. This greatly aids most developers to be able to discover something IF they can get close to the member name, irrespective of the namespace it is under.

  1. Rust has some luxury in being that it's a separate crate. Particularly they can add as many as they want and not worry about crate size or app size since Rust apps are statically linked and trimmed by default.

I guess because they'll be used in the box, we cannot have a separate NuGet package?

alexrp commented 1 year ago

If this API proposal is accepted, I'd like to also see 1.3.6.1.5.5.7.3.1 (serverAuth) and 1.3.6.1.5.5.7.3.2 (clientAuth).

ThreeSevenths commented 3 months ago

Will this be made public in .NET9?

ergunr commented 3 months ago

Se la sont totalement priver, ça ne vous regarde pas je suis que sur ma page et pas celle des autres devant la loi personne ne pourras m'empècher sais pas a vous de me dire se que je doit faire et bon débarras avec vous mércie


De : Trevor Davis @.> Envoyé : jeudi 30 mai 2024 17:42 À : dotnet/runtime @.> Cc : Subscribed @.***> Objet : Re: [dotnet/runtime] [API Proposal]: Make System.Security.Cryptography.Oids constants public (Issue #87270)

Will this be made public in .NET9?

— Reply to this email directly, view it on GitHubhttps://github.com/dotnet/runtime/issues/87270#issuecomment-2139992833, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AUW2LQ7KUFHYZTIT7COOYC3ZE5CE7AVCNFSM6AAAAAAY7GGG3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZZHE4TEOBTGM. You are receiving this because you are subscribed to this thread.Message ID: @.***>

vcsjones commented 3 months ago

Will this be made public in .NET9?

This still has yet to be a complete API proposal and go through an API review. In particular, every name needs to be appropriate for public API.