Support additional friendly names on ECC OIDs
authorKevin Jones <kevin@vcsjones.com>
Thu, 14 May 2020 15:28:44 +0000 (11:28 -0400)
committerGitHub <noreply@github.com>
Thu, 14 May 2020 15:28:44 +0000 (08:28 -0700)
Expand the name/OID table to support a m:m relationship (secp256r1 and nistP256 are both 1.2.840.10045.3.1.7; 1.3.14.7.2.3.1 and 1.2.840.113549.1.1.4 are both md5RSA) and add in the alternative names for the secp{size}r1 curves (size in 256, 384, 521).

src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.OSX.cs
src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs
src/libraries/System.Security.Cryptography.Encoding/tests/Oid.cs

index ee9cbb6..fb055ca 100644 (file)
@@ -67,6 +67,16 @@ namespace Internal.Cryptography
         private static readonly Dictionary<string, string> s_extraOidToFriendlyName =
             InvertWithDefaultComparer(s_extraFriendlyNameToOid);
 
+        private static Dictionary<string, string> InvertWithDefaultComparer(Dictionary<string, string> source)
+        {
+            var result = new Dictionary<string, string>(source.Count);
+            foreach (KeyValuePair<string, string> item in source)
+            {
+                result.Add(item.Value, item.Key);
+            }
+            return result;
+        }
+
 #if DEBUG
         static partial void ExtraStaticDebugValidation()
         {
index ca743d2..e852b14 100644 (file)
@@ -94,132 +94,16 @@ namespace Internal.Cryptography
         }
 
         /// <summary>Expected size of <see cref="s_friendlyNameToOid"/>.</summary>
-        private const int FriendlyNameToOidCount = 103;
+        private const int FriendlyNameToOidCount = 110;
+
+        /// <summary>Expected size of <see cref="s_oidToFriendlyName"/>.</summary>
+        private const int OidToFriendlyNameCount = 103;
 
-        // This table was originally built by extracting every szOID #define out of wincrypt.h,
-        // and running them through new Oid(string) on Windows 10.  Then, take the list of everything
-        // which produced a FriendlyName value, and run it through two other languages. If all 3 agree
-        // on the mapping, consider the value to be non-localized.
-        //
-        // This original list was produced on English (Win10), cross-checked with Spanish (Win8.1) and
-        // Japanese (Win10).
-        //
-        // Sometimes wincrypt.h has more than one OID which results in the same name.  The OIDs whose value
-        // doesn't roundtrip (new Oid(new Oid(value).FriendlyName).Value) are contained in s_compatOids.
-        //
-        // X-Plat: The names (and casing) in this table come from Windows. Part of the intent of this table
-        // is to prevent issues wherein an identifier is different between Windows and Unix;
-        // since any existing code would be using the Windows identifier, it is the de facto standard.
         private static readonly Dictionary<string, string> s_friendlyNameToOid =
-            new Dictionary<string, string>(FriendlyNameToOidCount, StringComparer.OrdinalIgnoreCase)
-            {
-                { "3des", "1.2.840.113549.3.7" },
-                { "aes128", "2.16.840.1.101.3.4.1.2" },
-                { "aes128wrap", "2.16.840.1.101.3.4.1.5" },
-                { "aes192", "2.16.840.1.101.3.4.1.22" },
-                { "aes192wrap", "2.16.840.1.101.3.4.1.25" },
-                { "aes256", "2.16.840.1.101.3.4.1.42" },
-                { "aes256wrap", "2.16.840.1.101.3.4.1.45" },
-                { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" },
-                { "brainpoolP160t1", "1.3.36.3.3.2.8.1.1.2" },
-                { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" },
-                { "brainpoolP192t1", "1.3.36.3.3.2.8.1.1.4" },
-                { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" },
-                { "brainpoolP224t1", "1.3.36.3.3.2.8.1.1.6" },
-                { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" },
-                { "brainpoolP256t1", "1.3.36.3.3.2.8.1.1.8" },
-                { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" },
-                { "brainpoolP320t1", "1.3.36.3.3.2.8.1.1.10" },
-                { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11" },
-                { "brainpoolP384t1", "1.3.36.3.3.2.8.1.1.12" },
-                { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13" },
-                { "brainpoolP512t1", "1.3.36.3.3.2.8.1.1.14" },
-                { "C", "2.5.4.6" },
-                { "CMS3DESwrap", "1.2.840.113549.1.9.16.3.6" },
-                { "CMSRC2wrap", "1.2.840.113549.1.9.16.3.7" },
-                { "CN", "2.5.4.3" },
-                { "CPS", "1.3.6.1.5.5.7.2.1" },
-                { "DC", "0.9.2342.19200300.100.1.25" },
-                { "des", "1.3.14.3.2.7" },
-                { "Description", "2.5.4.13" },
-                { "DH", "1.2.840.10046.2.1" },
-                { "dnQualifier", "2.5.4.46" },
-                { "DSA", "1.2.840.10040.4.1" },
-                { "dsaSHA1", "1.3.14.3.2.27" },
-                { "E", "1.2.840.113549.1.9.1" },
-                { "ec192wapi", "1.2.156.11235.1.1.2.1" },
-                { "ECC", "1.2.840.10045.2.1" },
-                { "ECDH_STD_SHA1_KDF", "1.3.133.16.840.63.0.2" },
-                { "ECDH_STD_SHA256_KDF", "1.3.132.1.11.1" },
-                { "ECDH_STD_SHA384_KDF", "1.3.132.1.11.2" },
-                { "ECDSA_P256", "1.2.840.10045.3.1.7" },
-                { "ECDSA_P384", "1.3.132.0.34" },
-                { "ECDSA_P521", "1.3.132.0.35" },
-                { "ESDH", "1.2.840.113549.1.9.16.3.5" },
-                { "G", "2.5.4.42" },
-                { "I", "2.5.4.43" },
-                { "L", "2.5.4.7" },
-                { "md2", "1.2.840.113549.2.2" },
-                { "md2RSA", "1.2.840.113549.1.1.2" },
-                { "md4", "1.2.840.113549.2.4" },
-                { "md4RSA", "1.2.840.113549.1.1.3" },
-                { "md5", "1.2.840.113549.2.5" },
-                { "md5RSA", "1.2.840.113549.1.1.4" },
-                { "mgf1", "1.2.840.113549.1.1.8" },
-                { "mosaicKMandUpdSig", "2.16.840.1.101.2.1.1.20" },
-                { "mosaicUpdatedSig", "2.16.840.1.101.2.1.1.19" },
-                { "nistP192", "1.2.840.10045.3.1.1" },
-                { "nistP224", "1.3.132.0.33" },
-                { "NO_SIGN", "1.3.6.1.5.5.7.6.2" },
-                { "O", "2.5.4.10" },
-                { "OU", "2.5.4.11" },
-                { "Phone", "2.5.4.20" },
-                { "POBox", "2.5.4.18" },
-                { "PostalCode", "2.5.4.17" },
-                { "rc2", "1.2.840.113549.3.2" },
-                { "rc4", "1.2.840.113549.3.4" },
-                { "RSA", "1.2.840.113549.1.1.1" },
-                { "RSAES_OAEP", "1.2.840.113549.1.1.7" },
-                { "RSASSA-PSS", "1.2.840.113549.1.1.10" },
-                { "S", "2.5.4.8" },
-                { "secP160k1", "1.3.132.0.9" },
-                { "secP160r1", "1.3.132.0.8" },
-                { "secP160r2", "1.3.132.0.30" },
-                { "secP192k1", "1.3.132.0.31" },
-                { "secP224k1", "1.3.132.0.32" },
-                { "secP256k1", "1.3.132.0.10" },
-                { "SERIALNUMBER", "2.5.4.5" },
-                { "sha1", "1.3.14.3.2.26" },
-                { "sha1DSA", "1.2.840.10040.4.3" },
-                { "sha1ECDSA", "1.2.840.10045.4.1" },
-                { "sha1RSA", "1.2.840.113549.1.1.5" },
-                { "sha256", "2.16.840.1.101.3.4.2.1" },
-                { "sha256ECDSA", "1.2.840.10045.4.3.2" },
-                { "sha256RSA", "1.2.840.113549.1.1.11" },
-                { "sha384", "2.16.840.1.101.3.4.2.2" },
-                { "sha384ECDSA", "1.2.840.10045.4.3.3" },
-                { "sha384RSA", "1.2.840.113549.1.1.12" },
-                { "sha512", "2.16.840.1.101.3.4.2.3" },
-                { "sha512ECDSA", "1.2.840.10045.4.3.4" },
-                { "sha512RSA", "1.2.840.113549.1.1.13" },
-                { "SN", "2.5.4.4" },
-                { "specifiedECDSA", "1.2.840.10045.4.3" },
-                { "STREET", "2.5.4.9" },
-                { "T", "2.5.4.12" },
-                { "TPMManufacturer", "2.23.133.2.1" },
-                { "TPMModel", "2.23.133.2.2" },
-                { "TPMVersion", "2.23.133.2.3" },
-                { "wtls9", "2.23.43.1.4.9" },
-                { "X21Address", "2.5.4.24" },
-                { "x962P192v2", "1.2.840.10045.3.1.2" },
-                { "x962P192v3", "1.2.840.10045.3.1.3" },
-                { "x962P239v1", "1.2.840.10045.3.1.4" },
-                { "x962P239v2", "1.2.840.10045.3.1.5" },
-                { "x962P239v3", "1.2.840.10045.3.1.6" },
-            };
+            new Dictionary<string, string>(FriendlyNameToOidCount, StringComparer.OrdinalIgnoreCase);
 
         private static readonly Dictionary<string, string> s_oidToFriendlyName =
-            InvertWithDefaultComparer(s_friendlyNameToOid);
+            new Dictionary<string, string>(OidToFriendlyNameCount, StringComparer.Ordinal);
 
         private static readonly Dictionary<string, string> s_compatOids =
             new Dictionary<string, string>
@@ -237,29 +121,155 @@ namespace Internal.Cryptography
                 { "1.3.14.7.2.3.1", "md2RSA" },
             };
 
-        private static Dictionary<string, string> InvertWithDefaultComparer(Dictionary<string, string> source)
-        {
-            var result = new Dictionary<string, string>(source.Count);
-            foreach (KeyValuePair<string, string> item in source)
-            {
-                result.Add(item.Value, item.Key);
-            }
-            return result;
-        }
-
-#if DEBUG
         static OidLookup()
         {
+            InitializeLookupDictionaries();
+#if DEBUG
             // Validate we hardcoded the right dictionary size
             Debug.Assert(s_friendlyNameToOid.Count == FriendlyNameToOidCount,
                 $"Expected {nameof(s_friendlyNameToOid)}.{nameof(s_friendlyNameToOid.Count)} == {FriendlyNameToOidCount}, got {s_friendlyNameToOid.Count}");
-            Debug.Assert(s_oidToFriendlyName.Count == FriendlyNameToOidCount,
-                $"Expected {nameof(s_oidToFriendlyName)}.{nameof(s_oidToFriendlyName.Count)} == {FriendlyNameToOidCount}, got {s_oidToFriendlyName.Count}");
+            Debug.Assert(s_oidToFriendlyName.Count == OidToFriendlyNameCount,
+                $"Expected {nameof(s_oidToFriendlyName)}.{nameof(s_oidToFriendlyName.Count)} == {OidToFriendlyNameCount}, got {s_oidToFriendlyName.Count}");
 
             ExtraStaticDebugValidation();
+#endif
+        }
+
+        private static void InitializeLookupDictionaries()
+        {
+            void AddEntry(string oid, string primaryFriendlyName, string[]? additionalFriendlyNames = null)
+            {
+                s_oidToFriendlyName.Add(oid, primaryFriendlyName);
+                s_friendlyNameToOid.Add(primaryFriendlyName, oid);
+
+                if (additionalFriendlyNames != null)
+                {
+                    foreach (var additionalName in additionalFriendlyNames)
+                    {
+                        s_friendlyNameToOid.Add(additionalName, oid);
+                    }
+                }
+            }
+
+            // This lookup was originally built by extracting every szOID #define out of wincrypt.h,
+            // and running them through new Oid(string) on Windows 10.  Then, take the list of everything
+            // which produced a FriendlyName value, and run it through two other languages. If all 3 agree
+            // on the mapping, consider the value to be non-localized.
+            //
+            // This original list was produced on English (Win10), cross-checked with Spanish (Win8.1) and
+            // Japanese (Win10).
+            //
+            // Sometimes wincrypt.h has more than one OID which results in the same name.  The OIDs whose value
+            // doesn't roundtrip (new Oid(new Oid(value).FriendlyName).Value) are contained in s_compatOids.
+            //
+            // X-Plat: The names (and casing) in this table come from Windows. Part of the intent of this table
+            // is to prevent issues wherein an identifier is different between Windows and Unix;
+            // since any existing code would be using the Windows identifier, it is the de facto standard.
+            AddEntry("1.2.840.113549.3.7", "3des");
+            AddEntry("2.16.840.1.101.3.4.1.2", "aes128");
+            AddEntry("2.16.840.1.101.3.4.1.5", "aes128wrap");
+            AddEntry("2.16.840.1.101.3.4.1.22", "aes192");
+            AddEntry("2.16.840.1.101.3.4.1.25", "aes192wrap");
+            AddEntry("2.16.840.1.101.3.4.1.42", "aes256");
+            AddEntry("2.16.840.1.101.3.4.1.45", "aes256wrap");
+            AddEntry("1.3.36.3.3.2.8.1.1.1", "brainpoolP160r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.2", "brainpoolP160t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.3", "brainpoolP192r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.4", "brainpoolP192t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.5", "brainpoolP224r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.6", "brainpoolP224t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.7", "brainpoolP256r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.8", "brainpoolP256t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.9", "brainpoolP320r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.10", "brainpoolP320t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.11", "brainpoolP384r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.12", "brainpoolP384t1");
+            AddEntry("1.3.36.3.3.2.8.1.1.13", "brainpoolP512r1");
+            AddEntry("1.3.36.3.3.2.8.1.1.14", "brainpoolP512t1");
+            AddEntry("2.5.4.6", "C");
+            AddEntry("1.2.840.113549.1.9.16.3.6", "CMS3DESwrap");
+            AddEntry("1.2.840.113549.1.9.16.3.7", "CMSRC2wrap");
+            AddEntry("2.5.4.3", "CN");
+            AddEntry("1.3.6.1.5.5.7.2.1", "CPS");
+            AddEntry("0.9.2342.19200300.100.1.25", "DC");
+            AddEntry("1.3.14.3.2.7", "des");
+            AddEntry("2.5.4.13", "Description");
+            AddEntry("1.2.840.10046.2.1", "DH");
+            AddEntry("2.5.4.46", "dnQualifier");
+            AddEntry("1.2.840.10040.4.1", "DSA");
+            AddEntry("1.3.14.3.2.27", "dsaSHA1");
+            AddEntry("1.2.840.113549.1.9.1", "E");
+            AddEntry("1.2.156.11235.1.1.2.1", "ec192wapi");
+            AddEntry("1.2.840.10045.2.1", "ECC");
+            AddEntry("1.3.133.16.840.63.0.2", "ECDH_STD_SHA1_KDF");
+            AddEntry("1.3.132.1.11.1", "ECDH_STD_SHA256_KDF");
+            AddEntry("1.3.132.1.11.2", "ECDH_STD_SHA384_KDF");
+            AddEntry("1.2.840.10045.3.1.7", "ECDSA_P256", new[] { "nistP256", "secP256r1", "x962P256v1" } );
+            AddEntry("1.3.132.0.34", "ECDSA_P384", new[] { "nistP384", "secP384r1" });
+            AddEntry("1.3.132.0.35", "ECDSA_P521", new[] { "nistP521", "secP521r1" });
+            AddEntry("1.2.840.113549.1.9.16.3.5", "ESDH");
+            AddEntry("2.5.4.42", "G");
+            AddEntry("2.5.4.43", "I");
+            AddEntry("2.5.4.7", "L");
+            AddEntry("1.2.840.113549.2.2", "md2");
+            AddEntry("1.2.840.113549.1.1.2", "md2RSA");
+            AddEntry("1.2.840.113549.2.4", "md4");
+            AddEntry("1.2.840.113549.1.1.3", "md4RSA");
+            AddEntry("1.2.840.113549.2.5", "md5");
+            AddEntry("1.2.840.113549.1.1.4", "md5RSA");
+            AddEntry("1.2.840.113549.1.1.8", "mgf1");
+            AddEntry("2.16.840.1.101.2.1.1.20", "mosaicKMandUpdSig");
+            AddEntry("2.16.840.1.101.2.1.1.19", "mosaicUpdatedSig");
+            AddEntry("1.2.840.10045.3.1.1", "nistP192");
+            AddEntry("1.3.132.0.33", "nistP224");
+            AddEntry("1.3.6.1.5.5.7.6.2", "NO_SIGN");
+            AddEntry("2.5.4.10", "O");
+            AddEntry("2.5.4.11", "OU");
+            AddEntry("2.5.4.20", "Phone");
+            AddEntry("2.5.4.18", "POBox");
+            AddEntry("2.5.4.17", "PostalCode");
+            AddEntry("1.2.840.113549.3.2", "rc2");
+            AddEntry("1.2.840.113549.3.4", "rc4");
+            AddEntry("1.2.840.113549.1.1.1", "RSA");
+            AddEntry("1.2.840.113549.1.1.7", "RSAES_OAEP");
+            AddEntry("1.2.840.113549.1.1.10", "RSASSA-PSS");
+            AddEntry("2.5.4.8", "S");
+            AddEntry("1.3.132.0.9", "secP160k1");
+            AddEntry("1.3.132.0.8", "secP160r1");
+            AddEntry("1.3.132.0.30", "secP160r2");
+            AddEntry("1.3.132.0.31", "secP192k1");
+            AddEntry("1.3.132.0.32", "secP224k1");
+            AddEntry("1.3.132.0.10", "secP256k1");
+            AddEntry("2.5.4.5", "SERIALNUMBER");
+            AddEntry("1.3.14.3.2.26", "sha1");
+            AddEntry("1.2.840.10040.4.3", "sha1DSA");
+            AddEntry("1.2.840.10045.4.1", "sha1ECDSA");
+            AddEntry("1.2.840.113549.1.1.5", "sha1RSA");
+            AddEntry("2.16.840.1.101.3.4.2.1", "sha256");
+            AddEntry("1.2.840.10045.4.3.2", "sha256ECDSA");
+            AddEntry("1.2.840.113549.1.1.11", "sha256RSA");
+            AddEntry("2.16.840.1.101.3.4.2.2", "sha384");
+            AddEntry("1.2.840.10045.4.3.3", "sha384ECDSA");
+            AddEntry("1.2.840.113549.1.1.12", "sha384RSA");
+            AddEntry("2.16.840.1.101.3.4.2.3", "sha512");
+            AddEntry("1.2.840.10045.4.3.4", "sha512ECDSA");
+            AddEntry("1.2.840.113549.1.1.13", "sha512RSA");
+            AddEntry("2.5.4.4", "SN");
+            AddEntry("1.2.840.10045.4.3", "specifiedECDSA");
+            AddEntry("2.5.4.9", "STREET");
+            AddEntry("2.5.4.12", "T");
+            AddEntry("2.23.133.2.1", "TPMManufacturer");
+            AddEntry("2.23.133.2.2", "TPMModel");
+            AddEntry("2.23.133.2.3", "TPMVersion");
+            AddEntry("2.23.43.1.4.9", "wtls9");
+            AddEntry("2.5.4.24", "X21Address");
+            AddEntry("1.2.840.10045.3.1.2", "x962P192v2");
+            AddEntry("1.2.840.10045.3.1.3", "x962P192v3");
+            AddEntry("1.2.840.10045.3.1.4", "x962P239v1");
+            AddEntry("1.2.840.10045.3.1.5", "x962P239v2");
+            AddEntry("1.2.840.10045.3.1.6", "x962P239v3");
         }
 
         static partial void ExtraStaticDebugValidation();
-#endif
     }
 }
index 6e6b04f..cafaa03 100644 (file)
@@ -330,6 +330,21 @@ namespace System.Security.Cryptography.Encoding.Tests
             Assert.Equal(ObsoleteSmime3desWrap_Name, oid.FriendlyName);
         }
 
+        [Theory]
+        [InlineData("nistP256", "1.2.840.10045.3.1.7")]
+        [InlineData("secP256r1", "1.2.840.10045.3.1.7")]
+        [InlineData("x962P256v1", "1.2.840.10045.3.1.7")]
+        [InlineData("nistP384", "1.3.132.0.34")]
+        [InlineData("secP384r1", "1.3.132.0.34")]
+        [InlineData("nistP521", "1.3.132.0.35")]
+        [InlineData("secP521r1", "1.3.132.0.35")]
+        public static void LookupOidByFriendlyName_AdditionalNames(string friendlyName, string expectedOid)
+        {
+            Oid oid = Oid.FromFriendlyName(friendlyName, OidGroup.All);
+            Assert.Equal(friendlyName, oid.FriendlyName);
+            Assert.Equal(expectedOid, oid.Value);
+        }
+
         public static IEnumerable<object[]> ValidOidFriendlyNamePairs
         {
             get