|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Runtime.Versioning;
namespace System.Security.Cryptography
{
public partial class CryptoConfig
{
#if !BROWSER
private const string AssemblyName_Pkcs = "System.Security.Cryptography.Pkcs";
private const BindingFlags ConstructorDefault = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
private const string OID_RSA_SMIMEalgCMS3DESwrap = "1.2.840.113549.1.9.16.3.6";
private const string OID_RSA_MD5 = "1.2.840.113549.2.5";
private const string OID_RSA_RC2CBC = "1.2.840.113549.3.2";
private const string OID_RSA_DES_EDE3_CBC = "1.2.840.113549.3.7";
private const string OID_OIWSEC_desCBC = "1.3.14.3.2.7";
private const string OID_OIWSEC_SHA1 = "1.3.14.3.2.26";
private const string OID_OIWSEC_SHA256 = "2.16.840.1.101.3.4.2.1";
private const string OID_OIWSEC_SHA384 = "2.16.840.1.101.3.4.2.2";
private const string OID_OIWSEC_SHA512 = "2.16.840.1.101.3.4.2.3";
private const string OID_OIWSEC_RIPEMD160 = "1.3.36.3.2.1";
private const string ECDsaIdentifier = "ECDsa";
private static volatile Dictionary<string, string>? s_defaultOidHT;
private static volatile Dictionary<string, object>? s_defaultNameHT;
private static readonly ConcurrentDictionary<string, Type> appNameHT = new ConcurrentDictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
private static readonly ConcurrentDictionary<string, string> appOidHT = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private static Dictionary<string, string> DefaultOidHT
{
get
{
if (s_defaultOidHT != null)
{
return s_defaultOidHT;
}
int capacity = 37;
Dictionary<string, string> ht = new Dictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
ht.Add("SHA", OID_OIWSEC_SHA1);
ht.Add("SHA1", OID_OIWSEC_SHA1);
ht.Add("System.Security.Cryptography.SHA1", OID_OIWSEC_SHA1);
ht.Add("System.Security.Cryptography.SHA1CryptoServiceProvider", OID_OIWSEC_SHA1);
ht.Add("System.Security.Cryptography.SHA1Cng", OID_OIWSEC_SHA1);
ht.Add("System.Security.Cryptography.SHA1Managed", OID_OIWSEC_SHA1);
ht.Add("SHA256", OID_OIWSEC_SHA256);
ht.Add("System.Security.Cryptography.SHA256", OID_OIWSEC_SHA256);
ht.Add("System.Security.Cryptography.SHA256CryptoServiceProvider", OID_OIWSEC_SHA256);
ht.Add("System.Security.Cryptography.SHA256Cng", OID_OIWSEC_SHA256);
ht.Add("System.Security.Cryptography.SHA256Managed", OID_OIWSEC_SHA256);
ht.Add("SHA384", OID_OIWSEC_SHA384);
ht.Add("System.Security.Cryptography.SHA384", OID_OIWSEC_SHA384);
ht.Add("System.Security.Cryptography.SHA384CryptoServiceProvider", OID_OIWSEC_SHA384);
ht.Add("System.Security.Cryptography.SHA384Cng", OID_OIWSEC_SHA384);
ht.Add("System.Security.Cryptography.SHA384Managed", OID_OIWSEC_SHA384);
ht.Add("SHA512", OID_OIWSEC_SHA512);
ht.Add("System.Security.Cryptography.SHA512", OID_OIWSEC_SHA512);
ht.Add("System.Security.Cryptography.SHA512CryptoServiceProvider", OID_OIWSEC_SHA512);
ht.Add("System.Security.Cryptography.SHA512Cng", OID_OIWSEC_SHA512);
ht.Add("System.Security.Cryptography.SHA512Managed", OID_OIWSEC_SHA512);
ht.Add("RIPEMD160", OID_OIWSEC_RIPEMD160);
ht.Add("System.Security.Cryptography.RIPEMD160", OID_OIWSEC_RIPEMD160);
ht.Add("System.Security.Cryptography.RIPEMD160Managed", OID_OIWSEC_RIPEMD160);
ht.Add("MD5", OID_RSA_MD5);
ht.Add("System.Security.Cryptography.MD5", OID_RSA_MD5);
ht.Add("System.Security.Cryptography.MD5CryptoServiceProvider", OID_RSA_MD5);
ht.Add("System.Security.Cryptography.MD5Managed", OID_RSA_MD5);
ht.Add("TripleDESKeyWrap", OID_RSA_SMIMEalgCMS3DESwrap);
ht.Add("RC2", OID_RSA_RC2CBC);
ht.Add("System.Security.Cryptography.RC2CryptoServiceProvider", OID_RSA_RC2CBC);
ht.Add("DES", OID_OIWSEC_desCBC);
ht.Add("System.Security.Cryptography.DESCryptoServiceProvider", OID_OIWSEC_desCBC);
ht.Add("TripleDES", OID_RSA_DES_EDE3_CBC);
ht.Add("System.Security.Cryptography.TripleDESCryptoServiceProvider", OID_RSA_DES_EDE3_CBC);
Debug.Assert(ht.Count <= capacity); // if more entries are added in the future, increase initial capacity.
s_defaultOidHT = ht;
return s_defaultOidHT;
}
}
private static Dictionary<string, object> DefaultNameHT
{
get
{
if (s_defaultNameHT != null)
{
return s_defaultNameHT;
}
const int capacity = 89;
Dictionary<string, object> ht = new Dictionary<string, object>(capacity: capacity, comparer: StringComparer.OrdinalIgnoreCase);
Type HMACMD5Type = typeof(System.Security.Cryptography.HMACMD5);
Type HMACSHA1Type = typeof(System.Security.Cryptography.HMACSHA1);
Type HMACSHA256Type = typeof(System.Security.Cryptography.HMACSHA256);
Type HMACSHA384Type = typeof(System.Security.Cryptography.HMACSHA384);
Type HMACSHA512Type = typeof(System.Security.Cryptography.HMACSHA512);
#pragma warning disable SYSLIB0022 // Rijndael types are obsolete
Type RijndaelManagedType = typeof(System.Security.Cryptography.RijndaelManaged);
#pragma warning restore SYSLIB0022
#pragma warning disable SYSLIB0021 // Obsolete: derived cryptographic types
Type AesManagedType = typeof(System.Security.Cryptography.AesManaged);
Type SHA256DefaultType = typeof(System.Security.Cryptography.SHA256Managed);
Type SHA384DefaultType = typeof(System.Security.Cryptography.SHA384Managed);
Type SHA512DefaultType = typeof(System.Security.Cryptography.SHA512Managed);
Type SHA1CryptoServiceProviderType = typeof(SHA1CryptoServiceProvider);
Type MD5CryptoServiceProviderType = typeof(MD5CryptoServiceProvider);
Type RSACryptoServiceProviderType = typeof(RSACryptoServiceProvider);
Type DSACryptoServiceProviderType = typeof(DSACryptoServiceProvider);
Type DESCryptoServiceProviderType = typeof(DESCryptoServiceProvider);
Type TripleDESCryptoServiceProviderType = typeof(TripleDESCryptoServiceProvider);
Type RC2CryptoServiceProviderType = typeof(RC2CryptoServiceProvider);
Type AesCryptoServiceProviderType = typeof(AesCryptoServiceProvider);
#pragma warning restore SYSLIB0021
#pragma warning disable SYSLIB0023 // RNGCryptoServiceProvider is obsolete
Type RNGCryptoServiceProviderType = typeof(RNGCryptoServiceProvider);
#pragma warning restore SYSLIB0023
Type ECDsaCngType = typeof(ECDsaCng);
// Random number generator
ht.Add("RandomNumberGenerator", RNGCryptoServiceProviderType);
ht.Add("System.Security.Cryptography.RandomNumberGenerator", RNGCryptoServiceProviderType);
// Hash functions
ht.Add("SHA", SHA1CryptoServiceProviderType);
ht.Add("SHA1", SHA1CryptoServiceProviderType);
ht.Add("System.Security.Cryptography.SHA1", SHA1CryptoServiceProviderType);
ht.Add("System.Security.Cryptography.HashAlgorithm", SHA1CryptoServiceProviderType);
ht.Add("MD5", MD5CryptoServiceProviderType);
ht.Add("System.Security.Cryptography.MD5", MD5CryptoServiceProviderType);
ht.Add("SHA256", SHA256DefaultType);
ht.Add("SHA-256", SHA256DefaultType);
ht.Add("System.Security.Cryptography.SHA256", SHA256DefaultType);
ht.Add("SHA384", SHA384DefaultType);
ht.Add("SHA-384", SHA384DefaultType);
ht.Add("System.Security.Cryptography.SHA384", SHA384DefaultType);
ht.Add("SHA512", SHA512DefaultType);
ht.Add("SHA-512", SHA512DefaultType);
ht.Add("System.Security.Cryptography.SHA512", SHA512DefaultType);
// Keyed Hash Algorithms
ht.Add("System.Security.Cryptography.HMAC", HMACSHA1Type);
ht.Add("System.Security.Cryptography.KeyedHashAlgorithm", HMACSHA1Type);
ht.Add("HMACMD5", HMACMD5Type);
ht.Add("System.Security.Cryptography.HMACMD5", HMACMD5Type);
ht.Add("HMACSHA1", HMACSHA1Type);
ht.Add("System.Security.Cryptography.HMACSHA1", HMACSHA1Type);
ht.Add("HMACSHA256", HMACSHA256Type);
ht.Add("System.Security.Cryptography.HMACSHA256", HMACSHA256Type);
ht.Add("HMACSHA384", HMACSHA384Type);
ht.Add("System.Security.Cryptography.HMACSHA384", HMACSHA384Type);
ht.Add("HMACSHA512", HMACSHA512Type);
ht.Add("System.Security.Cryptography.HMACSHA512", HMACSHA512Type);
// Asymmetric algorithms
ht.Add("RSA", RSACryptoServiceProviderType);
ht.Add("System.Security.Cryptography.RSA", RSACryptoServiceProviderType);
ht.Add("System.Security.Cryptography.AsymmetricAlgorithm", RSACryptoServiceProviderType);
if (!OperatingSystem.IsIOS() &&
!OperatingSystem.IsTvOS())
{
ht.Add("DSA", DSACryptoServiceProviderType);
ht.Add("System.Security.Cryptography.DSA", DSACryptoServiceProviderType);
}
// Windows will register the public ECDsaCng type. Non-Windows gets a special handler.
if (OperatingSystem.IsWindows())
{
ht.Add(ECDsaIdentifier, ECDsaCngType);
}
ht.Add("ECDsaCng", ECDsaCngType);
ht.Add("System.Security.Cryptography.ECDsaCng", ECDsaCngType);
// Symmetric algorithms
ht.Add("DES", DESCryptoServiceProviderType);
ht.Add("System.Security.Cryptography.DES", DESCryptoServiceProviderType);
ht.Add("3DES", TripleDESCryptoServiceProviderType);
ht.Add("TripleDES", TripleDESCryptoServiceProviderType);
ht.Add("Triple DES", TripleDESCryptoServiceProviderType);
ht.Add("System.Security.Cryptography.TripleDES", TripleDESCryptoServiceProviderType);
ht.Add("RC2", RC2CryptoServiceProviderType);
ht.Add("System.Security.Cryptography.RC2", RC2CryptoServiceProviderType);
ht.Add("Rijndael", RijndaelManagedType);
ht.Add("System.Security.Cryptography.Rijndael", RijndaelManagedType);
// Rijndael is the default symmetric cipher because (a) it's the strongest and (b) we know we have an implementation everywhere
ht.Add("System.Security.Cryptography.SymmetricAlgorithm", RijndaelManagedType);
ht.Add("AES", AesCryptoServiceProviderType);
ht.Add("AesCryptoServiceProvider", AesCryptoServiceProviderType);
ht.Add("System.Security.Cryptography.AesCryptoServiceProvider", AesCryptoServiceProviderType);
ht.Add("AesManaged", AesManagedType);
ht.Add("System.Security.Cryptography.AesManaged", AesManagedType);
// Xml Dsig/ Enc Hash algorithms
ht.Add("http://www.w3.org/2000/09/xmldsig#sha1", SHA1CryptoServiceProviderType);
// Add the other hash algorithms introduced with XML Encryption
ht.Add("http://www.w3.org/2001/04/xmlenc#sha256", SHA256DefaultType);
ht.Add("http://www.w3.org/2001/04/xmlenc#sha512", SHA512DefaultType);
// Xml Encryption symmetric keys
ht.Add("http://www.w3.org/2001/04/xmlenc#des-cbc", DESCryptoServiceProviderType);
ht.Add("http://www.w3.org/2001/04/xmlenc#tripledes-cbc", TripleDESCryptoServiceProviderType);
ht.Add("http://www.w3.org/2001/04/xmlenc#kw-tripledes", TripleDESCryptoServiceProviderType);
ht.Add("http://www.w3.org/2001/04/xmlenc#aes128-cbc", RijndaelManagedType);
ht.Add("http://www.w3.org/2001/04/xmlenc#kw-aes128", RijndaelManagedType);
ht.Add("http://www.w3.org/2001/04/xmlenc#aes192-cbc", RijndaelManagedType);
ht.Add("http://www.w3.org/2001/04/xmlenc#kw-aes192", RijndaelManagedType);
ht.Add("http://www.w3.org/2001/04/xmlenc#aes256-cbc", RijndaelManagedType);
ht.Add("http://www.w3.org/2001/04/xmlenc#kw-aes256", RijndaelManagedType);
// Xml Dsig HMAC URIs from http://www.w3.org/TR/xmldsig-core/
ht.Add("http://www.w3.org/2000/09/xmldsig#hmac-sha1", HMACSHA1Type);
// Xml Dsig-more Uri's as defined in http://www.ietf.org/rfc/rfc4051.txt
ht.Add("http://www.w3.org/2001/04/xmldsig-more#md5", MD5CryptoServiceProviderType);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#sha384", SHA384DefaultType);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-md5", HMACMD5Type);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", HMACSHA256Type);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-sha384", HMACSHA384Type);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-sha512", HMACSHA512Type);
// X509 Extensions (custom decoders)
ht.Add("2.5.29.10", typeof(X509Certificates.X509BasicConstraintsExtension));
ht.Add("2.5.29.19", typeof(X509Certificates.X509BasicConstraintsExtension));
ht.Add("2.5.29.14", typeof(X509Certificates.X509SubjectKeyIdentifierExtension));
ht.Add("2.5.29.15", typeof(X509Certificates.X509KeyUsageExtension));
ht.Add("2.5.29.35", typeof(X509Certificates.X509AuthorityKeyIdentifierExtension));
ht.Add("2.5.29.37", typeof(X509Certificates.X509EnhancedKeyUsageExtension));
ht.Add(Oids.AuthorityInformationAccess, typeof(X509Certificates.X509AuthorityInformationAccessExtension));
ht.Add(Oids.SubjectAltName, typeof(X509Certificates.X509SubjectAlternativeNameExtension));
// X509Chain class can be overridden to use a different chain engine.
ht.Add("X509Chain", typeof(X509Certificates.X509Chain));
// PKCS9 attributes
ht.Add("1.2.840.113549.1.9.3", "System.Security.Cryptography.Pkcs.Pkcs9ContentType, " + AssemblyName_Pkcs);
ht.Add("1.2.840.113549.1.9.4", "System.Security.Cryptography.Pkcs.Pkcs9MessageDigest, " + AssemblyName_Pkcs);
ht.Add("1.2.840.113549.1.9.5", "System.Security.Cryptography.Pkcs.Pkcs9SigningTime, " + AssemblyName_Pkcs);
ht.Add("1.3.6.1.4.1.311.88.2.1", "System.Security.Cryptography.Pkcs.Pkcs9DocumentName, " + AssemblyName_Pkcs);
ht.Add("1.3.6.1.4.1.311.88.2.2", "System.Security.Cryptography.Pkcs.Pkcs9DocumentDescription, " + AssemblyName_Pkcs);
Debug.Assert(ht.Count <= capacity); // // if more entries are added in the future, increase initial capacity.
s_defaultNameHT = ht;
return s_defaultNameHT;
// Types in .NET Framework but currently unsupported in .NET Core:
// Type HMACRIPEMD160Type = typeof(System.Security.Cryptography.HMACRIPEMD160);
// Type MAC3DESType = typeof(System.Security.Cryptography.MACTripleDES);
// Type DSASignatureDescriptionType = typeof(System.Security.Cryptography.DSASignatureDescription);
// Type RSAPKCS1SHA1SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA1SignatureDescription);
// Type RSAPKCS1SHA256SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA256SignatureDescription);
// Type RSAPKCS1SHA384SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA384SignatureDescription);
// Type RSAPKCS1SHA512SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA512SignatureDescription);
// string RIPEMD160ManagedType = "System.Security.Cryptography.RIPEMD160Managed" + AssemblyName_Encoding;
// string ECDiffieHellmanCngType = "System.Security.Cryptography.ECDiffieHellmanCng, " + AssemblyName_Cng;
// string MD5CngType = "System.Security.Cryptography.MD5Cng, " + AssemblyName_Cng;
// string SHA1CngType = "System.Security.Cryptography.SHA1Cng, " + AssemblyName_Cng;
// string SHA256CngType = "System.Security.Cryptography.SHA256Cng, " + AssemblyName_Cng;
// string SHA384CngType = "System.Security.Cryptography.SHA384Cng, " + AssemblyName_Cng;
// string SHA512CngType = "System.Security.Cryptography.SHA512Cng, " + AssemblyName_Cng;
// string SHA256CryptoServiceProviderType = "System.Security.Cryptography.SHA256CryptoServiceProvider, " + AssemblyName_Csp;
// string SHA384CryptoSerivceProviderType = "System.Security.Cryptography.SHA384CryptoServiceProvider, " + AssemblyName_Csp;
// string SHA512CryptoServiceProviderType = "System.Security.Cryptography.SHA512CryptoServiceProvider, " + AssemblyName_Csp;
// string DpapiDataProtectorType = "System.Security.Cryptography.DpapiDataProtector, " + AssemblyRef.SystemSecurity;
}
}
#endif
[UnsupportedOSPlatform("browser")]
public static void AddAlgorithm(Type algorithm, params string[] names)
{
#if BROWSER
throw new PlatformNotSupportedException(SR.SystemSecurityCryptography_PlatformNotSupported);
#else
ArgumentNullException.ThrowIfNull(algorithm);
if (!algorithm.IsVisible)
throw new ArgumentException(SR.Cryptography_AlgorithmTypesMustBeVisible, nameof(algorithm));
ArgumentNullException.ThrowIfNull(names);
string[] algorithmNames = new string[names.Length];
Array.Copy(names, algorithmNames, algorithmNames.Length);
// Pre-check the algorithm names for validity so that we don't add a few of the names and then
// throw an exception if we find an invalid name partway through the list.
foreach (string name in algorithmNames)
{
ArgumentException.ThrowIfNullOrEmpty(name, nameof(names));
}
// Everything looks valid, so we're safe to add the name mappings.
foreach (string name in algorithmNames)
{
appNameHT[name] = algorithm;
}
#endif
}
[RequiresUnreferencedCode("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")]
public static object? CreateFromName(string name, params object?[]? args)
{
ArgumentNullException.ThrowIfNull(name);
#if BROWSER
switch (name)
{
#pragma warning disable SYSLIB0021 // Obsolete: derived cryptographic types
// hardcode mapping for SHA* and HMAC* algorithm names from https://learn.microsoft.com/dotnet/api/system.security.cryptography.cryptoconfig?view=net-5.0#remarks
case "SHA":
case "SHA1":
case "System.Security.Cryptography.SHA1":
return new SHA1Managed();
case "SHA256":
case "SHA-256":
case "System.Security.Cryptography.SHA256":
return new SHA256Managed();
case "SHA384":
case "SHA-384":
case "System.Security.Cryptography.SHA384":
return new SHA384Managed();
case "SHA512":
case "SHA-512":
case "System.Security.Cryptography.SHA512":
return new SHA512Managed();
#pragma warning restore SYSLIB0021
case "System.Security.Cryptography.HMAC":
case "HMACSHA1":
case "System.Security.Cryptography.HMACSHA1":
case "System.Security.Cryptography.KeyedHashAlgorithm":
return new HMACSHA1();
case "HMACSHA256":
case "System.Security.Cryptography.HMACSHA256":
return new HMACSHA256();
case "HMACSHA384":
case "System.Security.Cryptography.HMACSHA384":
return new HMACSHA384();
case "HMACSHA512":
case "System.Security.Cryptography.HMACSHA512":
return new HMACSHA512();
}
return null;
#else
// Check to see if we have an application defined mapping
appNameHT.TryGetValue(name, out Type? retvalType);
// We allow the default table to Types and Strings
// Types get used for types in .Algorithms assembly.
// strings get used for delay-loaded stuff in other assemblies such as .Csp.
if (retvalType == null && DefaultNameHT.TryGetValue(name, out object? retvalObj))
{
retvalType = retvalObj as Type;
if (retvalType == null)
{
if (retvalObj is string retvalString)
{
retvalType = Type.GetType(retvalString, false, false);
if (retvalType != null && !retvalType.IsVisible)
{
retvalType = null;
}
if (retvalType != null)
{
// Add entry to the appNameHT, which makes subsequent calls much faster.
appNameHT[name] = retvalType;
}
}
else
{
Debug.Fail("Unsupported Dictionary value:" + retvalObj.ToString());
}
}
}
// Special case asking for "ECDsa" since the default map from .NET Framework uses
// a Windows-only type.
if (retvalType == null &&
(args == null || args.Length == 1) &&
name == ECDsaIdentifier)
{
return ECDsa.Create();
}
// Maybe they gave us a classname.
if (retvalType == null)
{
retvalType = Type.GetType(name, false, false);
if (retvalType != null && !retvalType.IsVisible)
{
retvalType = null;
}
}
// Still null? Then we didn't find it.
if (retvalType == null)
{
return null;
}
// Locate all constructors.
MethodBase[] cons = retvalType.GetConstructors(ConstructorDefault);
if (cons == null)
{
return null;
}
args ??= Array.Empty<object>();
List<MethodBase> candidates = new List<MethodBase>();
for (int i = 0; i < cons.Length; i++)
{
MethodBase con = cons[i];
if (con.GetParameters().Length == args.Length)
{
candidates.Add(con);
}
}
if (candidates.Count == 0)
{
return null;
}
cons = candidates.ToArray();
// Bind to matching ctor.
ConstructorInfo? rci = Type.DefaultBinder.BindToMethod(
ConstructorDefault,
cons,
ref args,
null,
null,
null,
out object? state) as ConstructorInfo;
// Check for ctor we don't like (non-existent, delegate or decorated with declarative linktime demand).
if (rci == null || typeof(Delegate).IsAssignableFrom(rci.DeclaringType))
{
return null;
}
// Ctor invoke and allocation.
object retval = rci.Invoke(ConstructorDefault, Type.DefaultBinder, args, null);
// Reset any parameter re-ordering performed by the binder.
if (state != null)
{
Type.DefaultBinder.ReorderArgumentArray(ref args, state);
}
return retval;
#endif
}
[RequiresUnreferencedCode(CreateFromNameUnreferencedCodeMessage)]
public static object? CreateFromName(string name)
{
return CreateFromName(name, null);
}
[UnsupportedOSPlatform("browser")]
public static void AddOID(string oid, params string[] names)
{
#if BROWSER
throw new PlatformNotSupportedException(SR.SystemSecurityCryptography_PlatformNotSupported);
#else
ArgumentNullException.ThrowIfNull(oid);
ArgumentNullException.ThrowIfNull(names);
string[] oidNames = new string[names.Length];
Array.Copy(names, oidNames, oidNames.Length);
// Pre-check the input names for validity, so that we don't add a few of the names and throw an
// exception if an invalid name is found further down the array.
foreach (string name in oidNames)
{
ArgumentException.ThrowIfNullOrEmpty(name, nameof(names));
}
// Everything is valid, so we're good to lock the hash table and add the application mappings
foreach (string name in oidNames)
{
appOidHT[name] = oid;
}
#endif
}
[UnsupportedOSPlatform("browser")]
public static string? MapNameToOID(string name)
{
#if BROWSER
throw new PlatformNotSupportedException(SR.SystemSecurityCryptography_PlatformNotSupported);
#else
ArgumentNullException.ThrowIfNull(name);
appOidHT.TryGetValue(name, out string? oidName);
if (string.IsNullOrEmpty(oidName) && !DefaultOidHT.TryGetValue(name, out oidName))
{
try
{
Oid oid = Oid.FromFriendlyName(name, OidGroup.All);
oidName = oid.Value;
}
catch (CryptographicException) { }
}
return oidName;
#endif
}
[UnsupportedOSPlatform("browser")]
[Obsolete(Obsoletions.CryptoConfigEncodeOIDMessage, DiagnosticId = Obsoletions.CryptoConfigEncodeOIDDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
public static byte[] EncodeOID(string str)
{
#if BROWSER
throw new PlatformNotSupportedException(SR.SystemSecurityCryptography_PlatformNotSupported);
#else
ArgumentNullException.ThrowIfNull(str);
string[] oidString = str.Split('.'); // valid ASN.1 separator
uint[] oidNums = new uint[oidString.Length];
for (int i = 0; i < oidString.Length; i++)
{
oidNums[i] = unchecked((uint)int.Parse(oidString[i], CultureInfo.InvariantCulture));
}
// Handle the first two oidNums special
if (oidNums.Length < 2)
throw new CryptographicUnexpectedOperationException(SR.Cryptography_InvalidOID);
uint firstTwoOidNums = unchecked((oidNums[0] * 40) + oidNums[1]);
// Determine length of output array
int encodedOidNumsLength = 2; // Reserve first two bytes for later
EncodeSingleOidNum(firstTwoOidNums, null, ref encodedOidNumsLength);
for (int i = 2; i < oidNums.Length; i++)
{
EncodeSingleOidNum(oidNums[i], null, ref encodedOidNumsLength);
}
// Allocate the array to receive encoded oidNums
byte[] encodedOidNums = new byte[encodedOidNumsLength];
int encodedOidNumsIndex = 2;
// Encode each segment
EncodeSingleOidNum(firstTwoOidNums, encodedOidNums, ref encodedOidNumsIndex);
for (int i = 2; i < oidNums.Length; i++)
{
EncodeSingleOidNum(oidNums[i], encodedOidNums, ref encodedOidNumsIndex);
}
Debug.Assert(encodedOidNumsIndex == encodedOidNumsLength);
// Final return value is 06 <length> encodedOidNums[]
if (encodedOidNumsIndex - 2 > 0x7f)
throw new CryptographicUnexpectedOperationException(SR.Cryptography_Config_EncodedOIDError);
encodedOidNums[0] = (byte)0x06;
encodedOidNums[1] = (byte)(encodedOidNumsIndex - 2);
return encodedOidNums;
#endif
}
#if !BROWSER
private static void EncodeSingleOidNum(uint value, byte[]? destination, ref int index)
{
// Write directly to destination starting at index, and update index based on how many bytes written.
// If destination is null, just return updated index.
if (unchecked((int)value) < 0x80)
{
if (destination != null)
{
destination[index++] = unchecked((byte)value);
}
else
{
index += 1;
}
}
else if (value < 0x4000)
{
if (destination != null)
{
destination[index++] = (byte)((value >> 7) | 0x80);
destination[index++] = (byte)(value & 0x7f);
}
else
{
index += 2;
}
}
else if (value < 0x200000)
{
if (destination != null)
{
unchecked
{
destination[index++] = (byte)((value >> 14) | 0x80);
destination[index++] = (byte)((value >> 7) | 0x80);
destination[index++] = (byte)(value & 0x7f);
}
}
else
{
index += 3;
}
}
else if (value < 0x10000000)
{
if (destination != null)
{
unchecked
{
destination[index++] = (byte)((value >> 21) | 0x80);
destination[index++] = (byte)((value >> 14) | 0x80);
destination[index++] = (byte)((value >> 7) | 0x80);
destination[index++] = (byte)(value & 0x7f);
}
}
else
{
index += 4;
}
}
else
{
if (destination != null)
{
unchecked
{
destination[index++] = (byte)((value >> 28) | 0x80);
destination[index++] = (byte)((value >> 21) | 0x80);
destination[index++] = (byte)((value >> 14) | 0x80);
destination[index++] = (byte)((value >> 7) | 0x80);
destination[index++] = (byte)(value & 0x7f);
}
}
else
{
index += 5;
}
}
}
#endif
}
}
|